summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/in_pcb.c18
-rw-r--r--sys/netinet/ip_input.c2
-rw-r--r--sys/netinet/ip_output.c13
-rw-r--r--sys/netinet/tcp_output.c7
-rw-r--r--sys/netinet/tcp_syncache.c6
-rw-r--r--sys/netinet6/icmp6.c11
-rw-r--r--sys/netinet6/ip6_forward.c54
-rw-r--r--sys/netinet6/ip6_output.c17
-rw-r--r--sys/netinet6/ipsec.c1177
-rw-r--r--sys/netinet6/ipsec.h70
-rw-r--r--sys/netinet6/ipsec6.h11
-rw-r--r--sys/netinet6/nd6.c4
-rw-r--r--sys/netinet6/nd6_nbr.c8
-rw-r--r--sys/netinet6/raw_ip6.c11
-rw-r--r--sys/netinet6/udp6_output.c6
-rw-r--r--sys/netinet6/udp6_usrreq.c6
-rw-r--r--sys/netkey/key.c1167
-rw-r--r--sys/netkey/key.h21
-rw-r--r--sys/netkey/key_debug.c25
-rw-r--r--sys/netkey/keydb.c79
-rw-r--r--sys/netkey/keydb.h23
21 files changed, 1655 insertions, 1081 deletions
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index ec51ad4..e473f2f 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -79,7 +79,6 @@
#include <netipsec/ipsec.h>
#include <netipsec/key.h>
-#define IPSEC
#endif /* FAST_IPSEC */
struct in_addr zeroin_addr;
@@ -162,7 +161,7 @@ in_pcballoc(so, pcbinfo, td)
struct thread *td;
{
register struct inpcb *inp;
-#ifdef IPSEC
+#if defined(IPSEC) || defined(FAST_IPSEC)
int error;
#endif
inp = uma_zalloc(pcbinfo->ipi_zone, M_NOWAIT | M_ZERO);
@@ -171,8 +170,12 @@ in_pcballoc(so, pcbinfo, td)
inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
inp->inp_pcbinfo = pcbinfo;
inp->inp_socket = so;
-#ifdef IPSEC
+#if defined(IPSEC) || defined(FAST_IPSEC)
+#ifdef FAST_IPSEC
error = ipsec_init_policy(so, &inp->inp_sp);
+#else
+ error = ipsec_init_pcbpolicy(so, &inp->inp_sp);
+#endif
if (error != 0) {
uma_zfree(pcbinfo->ipi_zone, inp);
return error;
@@ -473,6 +476,10 @@ in_pcbconnect(inp, nam, td)
inp->inp_faddr.s_addr = faddr;
inp->inp_fport = fport;
in_pcbrehash(inp);
+#ifdef IPSEC
+ if (inp->inp_socket->so_type == SOCK_STREAM)
+ ipsec_pcbconn(inp->inp_sp);
+#endif
if (anonport)
inp->inp_flags |= INP_ANONPORT;
return (0);
@@ -655,6 +662,9 @@ in_pcbdisconnect(inp)
in_pcbrehash(inp);
if (inp->inp_socket->so_state & SS_NOFDREF)
in_pcbdetach(inp);
+#ifdef IPSEC
+ ipsec_pcbdisconn(inp->inp_sp);
+#endif
}
void
@@ -664,7 +674,7 @@ in_pcbdetach(inp)
struct socket *so = inp->inp_socket;
struct inpcbinfo *ipi = inp->inp_pcbinfo;
-#ifdef IPSEC
+#if defined(IPSEC) || defined(FAST_IPSEC)
ipsec4_delete_pcbpolicy(inp);
#endif /*IPSEC*/
inp->inp_gencnt = ++ipi->ipi_gencnt;
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 2518154..09f3f41 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -492,7 +492,7 @@ tooshort:
/*
* Bypass packet filtering for packets from a tunnel (gif).
*/
- if (ipsec_gethist(m, NULL))
+ if (ipsec_getnhist(m))
goto pass;
#endif
#if defined(FAST_IPSEC) && !defined(IPSEC_FILTERGIF)
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index aedab7f..0831784 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -144,6 +144,7 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
struct in_addr pkt_dst;
#ifdef IPSEC
struct route iproute;
+ struct socket *so;
struct secpolicy *sp = NULL;
#endif
#ifdef FAST_IPSEC
@@ -195,6 +196,11 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
}
m = m0;
+#ifdef IPSEC
+ so = ipsec_getsocket(m);
+ (void)ipsec_setsocket(m, NULL);
+#endif /*IPSEC*/
+
M_ASSERTPKTHDR(m);
#ifndef FAST_IPSEC
KASSERT(ro != NULL, ("ip_output: no route, proto %d",
@@ -488,10 +494,11 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
sendit:
#ifdef IPSEC
/* get SP for this packet */
- if (inp == NULL)
- sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error);
+ if (so == NULL)
+ sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
+ flags, &error);
else
- sp = ipsec4_getpolicybypcb(m, IPSEC_DIR_OUTBOUND, inp, &error);
+ sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
if (sp == NULL) {
ipsecstat.out_inval++;
diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c
index 1267aaf..b7ddc23 100644
--- a/sys/netinet/tcp_output.c
+++ b/sys/netinet/tcp_output.c
@@ -880,6 +880,13 @@ send:
: NULL);
/* TODO: IPv6 IP6TOS_ECT bit on */
+#ifdef IPSEC
+ if (ipsec_setsocket(m, so) != 0) {
+ m_freem(m);
+ error = ENOBUFS;
+ goto out;
+ }
+#endif /*IPSEC*/
error = ip6_output(m,
tp->t_inpcb->in6p_outputopts,
&tp->t_inpcb->in6p_route,
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index 902e711..c83e9b2 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -96,7 +96,6 @@
#include <netipsec/ipsec6.h>
#endif
#include <netipsec/key.h>
-#define IPSEC
#endif /*FAST_IPSEC*/
#include <machine/in_cksum.h>
@@ -621,6 +620,11 @@ syncache_socket(sc, lso, m)
}
#ifdef IPSEC
/* copy old policy into new socket's */
+ if (ipsec_copy_pcbpolicy(sotoinpcb(lso)->inp_sp, inp->inp_sp))
+ printf("syncache_expand: could not copy policy\n");
+#endif
+#ifdef FAST_IPSEC
+ /* copy old policy into new socket's */
if (ipsec_copy_policy(sotoinpcb(lso)->inp_sp, inp->inp_sp))
printf("syncache_expand: could not copy policy\n");
#endif
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 0eb0377..96f3640 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -109,7 +109,6 @@
#ifdef FAST_IPSEC
#include <netipsec/ipsec.h>
#include <netipsec/key.h>
-#define IPSEC
#endif
#include <net/net_osdep.h>
@@ -2218,6 +2217,10 @@ icmp6_reflect(m, off)
*/
m->m_flags &= ~(M_BCAST|M_MCAST);
+#ifdef IPSEC
+ /* Don't lookup socket */
+ (void)ipsec_setsocket(m, NULL);
+#endif /* IPSEC */
#ifdef COMPAT_RFC1885
ip6_output(m, NULL, &icmp6_reflect_rt, 0, NULL, &outif, NULL);
@@ -2441,7 +2444,7 @@ icmp6_redirect_input(m, off)
sdst.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst);
-#ifdef IPSEC
+#if defined(IPSEC) || defined(FAST_IPSEC)
key_sa_routechange((struct sockaddr *)&sdst);
#endif
}
@@ -2725,6 +2728,10 @@ noredhdropt:;
sizeof(*ip6), ntohs(ip6->ip6_plen));
/* send the packet to outside... */
+#ifdef IPSEC
+ /* Don't lookup socket */
+ (void)ipsec_setsocket(m, NULL);
+#endif /* IPSEC */
ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 7e847e9..4f2a35c 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -109,14 +109,15 @@ ip6_forward(m, srcrt)
int srcrt;
{
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
- struct sockaddr_in6 *dst;
- struct rtentry *rt;
+ struct sockaddr_in6 *dst = NULL;
+ struct rtentry *rt = NULL;
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
u_int32_t srczone, dstzone;
#ifdef IPSEC
struct secpolicy *sp = NULL;
+ int ipsecrt = 0;
#endif
#ifdef IPSEC
@@ -253,9 +254,24 @@ ip6_forward(m, srcrt)
}
{
+ struct ipsecrequest *isr = NULL;
struct ipsec_output_state state;
/*
+ * when the kernel forwards a packet, it is not proper to apply
+ * IPsec transport mode to the packet is not proper. this check
+ * avoid from this.
+ * at present, if there is even a transport mode SA request in the
+ * security policy, the kernel does not apply IPsec to the packet.
+ * this check is not enough because the following case is valid.
+ * ipsec esp/tunnel/xxx-xxx/require esp/transport//require;
+ */
+ for (isr = sp->req; isr; isr = isr->next) {
+ if (isr->saidx.mode == IPSEC_MODE_TRANSPORT)
+ goto skip_ipsec;
+ }
+
+ /*
* All the extension headers will become inaccessible
* (since they can be encrypted).
* Don't panic, we need no more updates to extension headers
@@ -300,10 +316,22 @@ ip6_forward(m, srcrt)
m_freem(m);
return;
}
+
+ /* adjust pointer */
+ ip6 = mtod(m, struct ip6_hdr *);
+ dst = (struct sockaddr_in6 *)state.dst;
+ rt = state.ro ? state.ro->ro_rt : NULL;
+ if (dst != NULL && rt != NULL)
+ ipsecrt = 1;
}
skip_ipsec:
#endif /* IPSEC */
+#ifdef IPSEC
+ if (ipsecrt)
+ goto skip_routing;
+#endif
+
dst = (struct sockaddr_in6 *)&ip6_forward_rt.ro_dst;
if (!srcrt) {
/* ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst */
@@ -353,6 +381,9 @@ ip6_forward(m, srcrt)
}
}
rt = ip6_forward_rt.ro_rt;
+#ifdef IPSEC
+ skip_routing:;
+#endif
/*
* Scope check: if a packet can't be delivered to its destination
@@ -362,8 +393,18 @@ ip6_forward(m, srcrt)
* [draft-ietf-ipngwg-icmp-v3-02.txt, Section 3.1]
*/
if (in6_addr2zoneid(m->m_pkthdr.rcvif, &ip6->ip6_src, &srczone) ||
- in6_addr2zoneid(rt->rt_ifp, &ip6->ip6_src, &dstzone) ||
- srczone != dstzone) {
+ in6_addr2zoneid(rt->rt_ifp, &ip6->ip6_src, &dstzone)) {
+ /* XXX: this should not happen */
+ ip6stat.ip6s_cantforward++;
+ ip6stat.ip6s_badscope++;
+ m_freem(m);
+ return;
+ }
+ if (srczone != dstzone
+#ifdef IPSEC
+ && !ipsecrt
+#endif
+ ) {
ip6stat.ip6s_cantforward++;
ip6stat.ip6s_badscope++;
in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard);
@@ -399,7 +440,7 @@ ip6_forward(m, srcrt)
#ifdef IPSEC
/*
* When we do IPsec tunnel ingress, we need to play
- * with if_mtu value (decrement IPsec header size
+ * with the link value (decrement IPsec header size
* from mtu value). The code is much simpler than v4
* case, as we have the outgoing interface for
* encapsulated packet as "rt->rt_ifp".
@@ -439,6 +480,9 @@ ip6_forward(m, srcrt)
* modified by a redirect.
*/
if (rt->rt_ifp == m->m_pkthdr.rcvif && !srcrt &&
+#ifdef IPSEC
+ !ipsecrt &&
+#endif
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) {
if ((rt->rt_ifp->if_flags & IFF_POINTOPOINT) != 0) {
/*
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index bbb7a43..9665429 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -184,18 +184,21 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
struct route_in6 *ro_pmtu = NULL;
int hdrsplit = 0;
int needipsec = 0;
+#ifdef FAST_IPSEC
+ int needipsectun = 0;
+ struct secpolicy *sp = NULL;
+#endif /* FAST_IPSEC */
#ifdef IPSEC
int needipsectun = 0;
+ struct socket *so;
struct secpolicy *sp = NULL;
- ip6 = mtod(m, struct ip6_hdr *);
+ /* for AH processing. stupid to have "socket" variable in IP layer... */
+ so = ipsec_getsocket(m);
+ (void)ipsec_setsocket(m, NULL);
#endif /* IPSEC */
-#ifdef FAST_IPSEC
- int needipsectun = 0;
- struct secpolicy *sp = NULL;
ip6 = mtod(m, struct ip6_hdr *);
-#endif /* FAST_IPSEC */
#define MAKE_EXTHDR(hp, mp) \
do { \
@@ -235,10 +238,10 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
#ifdef IPSEC
/* get a security policy for this packet */
- if (inp == NULL)
+ if (so == NULL)
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
else
- sp = ipsec6_getpolicybypcb(m, IPSEC_DIR_OUTBOUND, inp, &error);
+ sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
if (sp == NULL) {
ipsec6stat.out_inval++;
diff --git a/sys/netinet6/ipsec.c b/sys/netinet6/ipsec.c
index fbff11c..4c96813 100644
--- a/sys/netinet6/ipsec.c
+++ b/sys/netinet6/ipsec.c
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipsec.c,v 1.103 2001/05/24 07:14:18 sakane Exp $ */
+/* $KAME: ipsec.c,v 1.204 2003/09/19 10:53:38 jinmei Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -119,22 +119,24 @@ int ip4_esp_trans_deflev = IPSEC_LEVEL_USE;
int ip4_esp_net_deflev = IPSEC_LEVEL_USE;
int ip4_ah_trans_deflev = IPSEC_LEVEL_USE;
int ip4_ah_net_deflev = IPSEC_LEVEL_USE;
-struct secpolicy ip4_def_policy;
+struct secpolicy *ip4_def_policy;
int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
int ip4_esp_randpad = -1;
-#ifdef SYSCTL_DECL
+static int sp_cachegen = 1; /* cache generation # */
+
SYSCTL_DECL(_net_inet_ipsec);
#ifdef INET6
SYSCTL_DECL(_net_inet6_ipsec6);
#endif
-#endif
/* net.inet.ipsec */
SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS,
stats, CTLFLAG_RD, &ipsecstat, ipsecstat, "");
+#if 0
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY,
- def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, "");
+ def_policy, CTLFLAG_RW, &ip4_def_policy->policy, 0, "");
+#endif
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev,
CTLFLAG_RW, &ip4_esp_trans_deflev, 0, "");
SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev,
@@ -162,15 +164,17 @@ int ip6_esp_trans_deflev = IPSEC_LEVEL_USE;
int ip6_esp_net_deflev = IPSEC_LEVEL_USE;
int ip6_ah_trans_deflev = IPSEC_LEVEL_USE;
int ip6_ah_net_deflev = IPSEC_LEVEL_USE;
-struct secpolicy ip6_def_policy;
+struct secpolicy *ip6_def_policy;
int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */
int ip6_esp_randpad = -1;
/* net.inet6.ipsec6 */
SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS,
stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, "");
+#if 0
SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY,
- def_policy, CTLFLAG_RW, &ip6_def_policy.policy, 0, "");
+ def_policy, CTLFLAG_RW, &ip6_def_policy->policy, 0, "");
+#endif
SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev,
CTLFLAG_RW, &ip6_esp_trans_deflev, 0, "");
SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev,
@@ -187,12 +191,13 @@ SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD,
esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, "");
#endif /* INET6 */
+static struct secpolicy *ipsec_checkpcbcache __P((struct mbuf *,
+ struct inpcbpolicy *, int));
+static int ipsec_fillpcbcache __P((struct inpcbpolicy *, struct mbuf *,
+ struct secpolicy *, int));
+static int ipsec_invalpcbcache __P((struct inpcbpolicy *, int));
static int ipsec_setspidx_mbuf
- __P((struct secpolicyindex *, u_int, u_int, struct mbuf *, int));
-static int ipsec4_setspidx_inpcb __P((struct mbuf *, struct inpcb *));
-#ifdef INET6
-static int ipsec6_setspidx_in6pcb __P((struct mbuf *, struct in6pcb *));
-#endif
+ __P((struct secpolicyindex *, int, struct mbuf *, int));
static int ipsec_setspidx __P((struct mbuf *, struct secpolicyindex *, int));
static void ipsec4_get_ulp __P((struct mbuf *, struct secpolicyindex *, int));
static int ipsec4_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
@@ -202,6 +207,9 @@ static int ipsec6_setspidx_ipaddr __P((struct mbuf *, struct secpolicyindex *));
#endif
static struct inpcbpolicy *ipsec_newpcbpolicy __P((void));
static void ipsec_delpcbpolicy __P((struct inpcbpolicy *));
+#if 0
+static int ipsec_deepcopy_pcbpolicy __P((struct inpcbpolicy *));
+#endif
static struct secpolicy *ipsec_deepcopy_policy __P((struct secpolicy *));
static int ipsec_set_policy
__P((struct secpolicy **, int, caddr_t, size_t, int));
@@ -221,6 +229,172 @@ static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *));
#ifdef INET6
static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
#endif
+static struct ipsecaux *ipsec_addaux __P((struct mbuf *));
+static struct ipsecaux *ipsec_findaux __P((struct mbuf *));
+static void ipsec_optaux __P((struct mbuf *, struct ipsecaux *));
+#ifdef INET
+static int ipsec4_checksa __P((struct ipsecrequest *,
+ struct ipsec_output_state *));
+#endif
+#ifdef INET6
+static int ipsec6_checksa __P((struct ipsecrequest *,
+ struct ipsec_output_state *, int));
+#endif
+
+/*
+ * try to validate and use cached policy on a pcb.
+ */
+static struct secpolicy *
+ipsec_checkpcbcache(m, pcbsp, dir)
+ struct mbuf *m;
+ struct inpcbpolicy *pcbsp;
+ int dir;
+{
+ struct secpolicyindex spidx;
+ struct timeval mono_time;
+
+ microtime(&mono_time);
+
+ switch (dir) {
+ case IPSEC_DIR_INBOUND:
+ case IPSEC_DIR_OUTBOUND:
+ case IPSEC_DIR_ANY:
+ break;
+ default:
+ return NULL;
+ }
+#ifdef DIAGNOSTIC
+ if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0]))
+ panic("dir too big in ipsec_checkpcbcache");
+#endif
+ /* SPD table change invalidates all the caches */
+ if (pcbsp->cachegen[dir] == 0 || sp_cachegen > pcbsp->cachegen[dir]) {
+ ipsec_invalpcbcache(pcbsp, dir);
+ return NULL;
+ }
+ if (!pcbsp->cache[dir])
+ return NULL;
+ if (pcbsp->cache[dir]->state != IPSEC_SPSTATE_ALIVE) {
+ ipsec_invalpcbcache(pcbsp, dir);
+ return NULL;
+ }
+ if ((pcbsp->cacheflags & IPSEC_PCBSP_CONNECTED) == 0) {
+ if (!pcbsp->cache[dir])
+ return NULL;
+ if (ipsec_setspidx(m, &spidx, 1) != 0)
+ return NULL;
+ if (bcmp(&pcbsp->cacheidx[dir], &spidx, sizeof(spidx))) {
+ if (!pcbsp->cache[dir]->spidx ||
+ !key_cmpspidx_withmask(pcbsp->cache[dir]->spidx,
+ &spidx))
+ return NULL;
+ pcbsp->cacheidx[dir] = spidx;
+ }
+ } else {
+ /*
+ * The pcb is connected, and the L4 code is sure that:
+ * - outgoing side uses inp_[lf]addr
+ * - incoming side looks up policy after inpcb lookup
+ * and address pair is known to be stable. We do not need
+ * to generate spidx again, nor check the address match again.
+ *
+ * For IPv4/v6 SOCK_STREAM sockets, this assumption holds
+ * and there are calls to ipsec_pcbconn() from in_pcbconnect().
+ */
+ }
+
+ pcbsp->cache[dir]->lastused = mono_time.tv_sec;
+ pcbsp->cache[dir]->refcnt++;
+ KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+ printf("DP ipsec_checkpcbcache cause refcnt++:%d SP:%p\n",
+ pcbsp->cache[dir]->refcnt, pcbsp->cache[dir]));
+ return pcbsp->cache[dir];
+}
+
+static int
+ipsec_fillpcbcache(pcbsp, m, sp, dir)
+ struct inpcbpolicy *pcbsp;
+ struct mbuf *m;
+ struct secpolicy *sp;
+ int dir;
+{
+
+ switch (dir) {
+ case IPSEC_DIR_INBOUND:
+ case IPSEC_DIR_OUTBOUND:
+ break;
+ default:
+ return EINVAL;
+ }
+#ifdef DIAGNOSTIC
+ if (dir >= sizeof(pcbsp->cache)/sizeof(pcbsp->cache[0]))
+ panic("dir too big in ipsec_checkpcbcache");
+#endif
+
+ if (pcbsp->cache[dir])
+ key_freesp(pcbsp->cache[dir]);
+ pcbsp->cache[dir] = NULL;
+ if (ipsec_setspidx(m, &pcbsp->cacheidx[dir], 1) != 0) {
+ return EINVAL;
+ }
+ pcbsp->cache[dir] = sp;
+ if (pcbsp->cache[dir]) {
+ pcbsp->cache[dir]->refcnt++;
+ KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
+ printf("DP ipsec_fillpcbcache cause refcnt++:%d SP:%p\n",
+ pcbsp->cache[dir]->refcnt, pcbsp->cache[dir]));
+ }
+ pcbsp->cachegen[dir] = sp_cachegen;
+
+ return 0;
+}
+
+static int
+ipsec_invalpcbcache(pcbsp, dir)
+ struct inpcbpolicy *pcbsp;
+ int dir;
+{
+ int i;
+
+ for (i = IPSEC_DIR_INBOUND; i <= IPSEC_DIR_OUTBOUND; i++) {
+ if (dir != IPSEC_DIR_ANY && i != dir)
+ continue;
+ if (pcbsp->cache[i])
+ key_freesp(pcbsp->cache[i]);
+ pcbsp->cache[i] = NULL;
+ pcbsp->cachegen[i] = 0;
+ bzero(&pcbsp->cacheidx[i], sizeof(pcbsp->cacheidx[i]));
+ }
+ return 0;
+}
+
+int
+ipsec_pcbconn(pcbsp)
+ struct inpcbpolicy *pcbsp;
+{
+
+ pcbsp->cacheflags |= IPSEC_PCBSP_CONNECTED;
+ ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
+ return 0;
+}
+
+int
+ipsec_pcbdisconn(pcbsp)
+ struct inpcbpolicy *pcbsp;
+{
+
+ pcbsp->cacheflags &= ~IPSEC_PCBSP_CONNECTED;
+ ipsec_invalpcbcache(pcbsp, IPSEC_DIR_ANY);
+ return 0;
+}
+
+int
+ipsec_invalpcbcacheall()
+{
+
+ sp_cachegen++;
+ return 0;
+}
/*
* For OUTBOUND packet having a socket. Searching SPD for packet,
@@ -235,34 +409,50 @@ static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *));
* NOTE: IPv6 mapped adddress concern is implemented here.
*/
struct secpolicy *
-ipsec4_getpolicybypcb(m, dir, inp, error)
+ipsec4_getpolicybysock(m, dir, so, error)
struct mbuf *m;
u_int dir;
- struct inpcb *inp;
+ struct socket *so;
int *error;
{
struct inpcbpolicy *pcbsp = NULL;
struct secpolicy *currsp = NULL; /* policy on socket */
struct secpolicy *kernsp = NULL; /* policy on kernel */
+ struct secpolicyindex spidx;
+ u_int16_t tag;
/* sanity check */
- if (m == NULL || inp == NULL || error == NULL)
+ if (m == NULL || so == NULL || error == NULL)
panic("ipsec4_getpolicybysock: NULL pointer was passed.");
- /* set spidx in pcb */
+ switch (so->so_proto->pr_domain->dom_family) {
+ case AF_INET:
+ pcbsp = sotoinpcb(so)->inp_sp;
+ break;
#ifdef INET6
- if (inp->inp_vflag & INP_IPV6PROTO)
- *error = ipsec6_setspidx_in6pcb(m, inp);
- else
+ case AF_INET6:
+ pcbsp = sotoin6pcb(so)->in6p_sp;
+ break;
#endif
- *error = ipsec4_setspidx_inpcb(m, inp);
- if (*error)
- return NULL;
- pcbsp = inp->inp_sp;
+ default:
+ panic("ipsec4_getpolicybysock: unsupported address family");
+ }
- /* sanity check */
+#ifdef DIAGNOSTIC
if (pcbsp == NULL)
panic("ipsec4_getpolicybysock: pcbsp is NULL.");
+#endif
+
+ tag = 0;
+
+ /* if we have a cached entry, and if it is still valid, use it. */
+ ipsecstat.spdcachelookup++;
+ currsp = ipsec_checkpcbcache(m, pcbsp, dir);
+ if (currsp) {
+ *error = 0;
+ return currsp;
+ }
+ ipsecstat.spdcachemiss++;
switch (dir) {
case IPSEC_DIR_INBOUND:
@@ -285,36 +475,32 @@ ipsec4_getpolicybypcb(m, dir, inp, error)
case IPSEC_POLICY_BYPASS:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
case IPSEC_POLICY_ENTRUST:
/* look for a policy in SPD */
- kernsp = key_allocsp(&currsp->spidx, dir);
-
- /* SP found */
- if (kernsp != NULL) {
+ if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
+ (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+ /* SP found */
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP ipsec4_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
return kernsp;
}
/* no SP found */
- if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD
- && ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO,
- "fixed system default policy: %d->%d\n",
- ip4_def_policy.policy, IPSEC_POLICY_NONE));
- ip4_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip4_def_policy.refcnt++;
+ ip4_def_policy->refcnt++;
*error = 0;
- return &ip4_def_policy;
-
+ ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
+ return ip4_def_policy;
+
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
default:
@@ -328,14 +514,14 @@ ipsec4_getpolicybypcb(m, dir, inp, error)
/* when non-privilieged socket */
/* look for a policy in SPD */
- kernsp = key_allocsp(&currsp->spidx, dir);
-
- /* SP found */
- if (kernsp != NULL) {
+ if (ipsec_setspidx_mbuf(&spidx, AF_INET, m, 1) == 0 &&
+ (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+ /* SP found */
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP ipsec4_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
return kernsp;
}
@@ -349,20 +535,15 @@ ipsec4_getpolicybypcb(m, dir, inp, error)
return NULL;
case IPSEC_POLICY_ENTRUST:
- if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD
- && ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO,
- "fixed system default policy: %d->%d\n",
- ip4_def_policy.policy, IPSEC_POLICY_NONE));
- ip4_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip4_def_policy.refcnt++;
+ ip4_def_policy->refcnt++;
*error = 0;
- return &ip4_def_policy;
+ ipsec_fillpcbcache(pcbsp, m, ip4_def_policy, dir);
+ return ip4_def_policy;
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
default:
@@ -374,19 +555,6 @@ ipsec4_getpolicybypcb(m, dir, inp, error)
/* NOTREACHED */
}
-struct secpolicy *
-ipsec4_getpolicybysock(m, dir, so, error)
- struct mbuf *m;
- u_int dir;
- struct socket *so;
- int *error;
-{
-
- if (so == NULL)
- panic("ipsec4_getpolicybysock: NULL pointer was passed.");
- return (ipsec4_getpolicybypcb(m, dir, sotoinpcb(so), error));
-}
-
/*
* For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet,
* and return a pointer to SP.
@@ -405,24 +573,28 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
int *error;
{
struct secpolicy *sp = NULL;
+ u_int16_t tag;
/* sanity check */
if (m == NULL || error == NULL)
panic("ipsec4_getpolicybyaddr: NULL pointer was passed.");
+ /* get a policy entry matched with the packet */
{
struct secpolicyindex spidx;
bzero(&spidx, sizeof(spidx));
/* make an index to look for a policy */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET, m,
+ *error = ipsec_setspidx_mbuf(&spidx, AF_INET, m,
(flag & IP_FORWARDING) ? 0 : 1);
if (*error != 0)
return NULL;
- sp = key_allocsp(&spidx, dir);
+ tag = 0;
+
+ sp = key_allocsp(tag, &spidx, dir);
}
/* SP found */
@@ -435,15 +607,9 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
}
/* no SP found */
- if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD &&
- ip4_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO, "fixed system default policy:%d->%d\n",
- ip4_def_policy.policy, IPSEC_POLICY_NONE));
- ip4_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip4_def_policy.refcnt++;
+ ip4_def_policy->refcnt++;
*error = 0;
- return &ip4_def_policy;
+ return ip4_def_policy;
}
#ifdef INET6
@@ -458,32 +624,44 @@ ipsec4_getpolicybyaddr(m, dir, flag, error)
* others: a pointer to SP
*/
struct secpolicy *
-ipsec6_getpolicybypcb(m, dir, inp, error)
+ipsec6_getpolicybysock(m, dir, so, error)
struct mbuf *m;
u_int dir;
- struct inpcb *inp;
+ struct socket *so;
int *error;
{
struct inpcbpolicy *pcbsp = NULL;
struct secpolicy *currsp = NULL; /* policy on socket */
struct secpolicy *kernsp = NULL; /* policy on kernel */
+ struct secpolicyindex spidx;
+ u_int16_t tag;
/* sanity check */
- if (m == NULL || inp == NULL || error == NULL)
+ if (m == NULL || so == NULL || error == NULL)
panic("ipsec6_getpolicybysock: NULL pointer was passed.");
#ifdef DIAGNOSTIC
- if ((inp->inp_vflag & INP_IPV6PROTO) == 0)
+ if (so->so_proto->pr_domain->dom_family != AF_INET6)
panic("ipsec6_getpolicybysock: socket domain != inet6");
#endif
- /* set spidx in pcb */
- ipsec6_setspidx_in6pcb(m, inp);
- pcbsp = inp->in6p_sp;
+ pcbsp = sotoin6pcb(so)->in6p_sp;
- /* sanity check */
+#ifdef DIAGNOSTIC
if (pcbsp == NULL)
panic("ipsec6_getpolicybysock: pcbsp is NULL.");
+#endif
+
+ tag = 0;
+
+ /* if we have a cached entry, and if it is still valid, use it. */
+ ipsec6stat.spdcachelookup++;
+ currsp = ipsec_checkpcbcache(m, pcbsp, dir);
+ if (currsp) {
+ *error = 0;
+ return currsp;
+ }
+ ipsec6stat.spdcachemiss++;
switch (dir) {
case IPSEC_DIR_INBOUND:
@@ -506,36 +684,32 @@ ipsec6_getpolicybypcb(m, dir, inp, error)
case IPSEC_POLICY_BYPASS:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
case IPSEC_POLICY_ENTRUST:
/* look for a policy in SPD */
- kernsp = key_allocsp(&currsp->spidx, dir);
-
- /* SP found */
- if (kernsp != NULL) {
+ if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
+ (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+ /* SP found */
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP ipsec6_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
return kernsp;
}
/* no SP found */
- if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
- && ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO,
- "fixed system default policy: %d->%d\n",
- ip6_def_policy.policy, IPSEC_POLICY_NONE));
- ip6_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip6_def_policy.refcnt++;
+ ip6_def_policy->refcnt++;
*error = 0;
- return &ip6_def_policy;
-
+ ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir);
+ return ip6_def_policy;
+
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
default:
@@ -549,14 +723,14 @@ ipsec6_getpolicybypcb(m, dir, inp, error)
/* when non-privilieged socket */
/* look for a policy in SPD */
- kernsp = key_allocsp(&currsp->spidx, dir);
-
- /* SP found */
- if (kernsp != NULL) {
+ if (ipsec_setspidx_mbuf(&spidx, AF_INET6, m, 1) == 0 &&
+ (kernsp = key_allocsp(tag, &spidx, dir)) != NULL) {
+ /* SP found */
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP ipsec6_getpolicybysock called "
"to allocate SP:%p\n", kernsp));
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, kernsp, dir);
return kernsp;
}
@@ -570,20 +744,15 @@ ipsec6_getpolicybypcb(m, dir, inp, error)
return NULL;
case IPSEC_POLICY_ENTRUST:
- if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
- && ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO,
- "fixed system default policy: %d->%d\n",
- ip6_def_policy.policy, IPSEC_POLICY_NONE));
- ip6_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip6_def_policy.refcnt++;
+ ip6_def_policy->refcnt++;
*error = 0;
- return &ip6_def_policy;
+ ipsec_fillpcbcache(pcbsp, m, ip6_def_policy, dir);
+ return ip6_def_policy;
case IPSEC_POLICY_IPSEC:
currsp->refcnt++;
*error = 0;
+ ipsec_fillpcbcache(pcbsp, m, currsp, dir);
return currsp;
default:
@@ -596,19 +765,6 @@ ipsec6_getpolicybypcb(m, dir, inp, error)
/* NOTREACHED */
}
-struct secpolicy *
-ipsec6_getpolicybysock(m, dir, so, error)
- struct mbuf *m;
- u_int dir;
- struct socket *so;
- int *error;
-{
-
- if (so == NULL)
- panic("ipsec6_getpolicybysock: NULL pointer was passed.");
- return (ipsec6_getpolicybypcb(m, dir, sotoin6pcb(so), error));
-}
-
/*
* For FORWADING packet or OUTBOUND without a socket. Searching SPD for packet,
* and return a pointer to SP.
@@ -633,24 +789,28 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
int *error;
{
struct secpolicy *sp = NULL;
+ u_int16_t tag;
/* sanity check */
if (m == NULL || error == NULL)
panic("ipsec6_getpolicybyaddr: NULL pointer was passed.");
+ /* get a policy entry matched with the packet */
{
struct secpolicyindex spidx;
bzero(&spidx, sizeof(spidx));
/* make an index to look for a policy */
- *error = ipsec_setspidx_mbuf(&spidx, dir, AF_INET6, m,
+ *error = ipsec_setspidx_mbuf(&spidx, AF_INET6, m,
(flag & IP_FORWARDING) ? 0 : 1);
if (*error != 0)
return NULL;
- sp = key_allocsp(&spidx, dir);
+ tag = 0;
+
+ sp = key_allocsp(tag, &spidx, dir);
}
/* SP found */
@@ -663,15 +823,9 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
}
/* no SP found */
- if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD
- && ip6_def_policy.policy != IPSEC_POLICY_NONE) {
- ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n",
- ip6_def_policy.policy, IPSEC_POLICY_NONE));
- ip6_def_policy.policy = IPSEC_POLICY_NONE;
- }
- ip6_def_policy.refcnt++;
+ ip6_def_policy->refcnt++;
*error = 0;
- return &ip6_def_policy;
+ return ip6_def_policy;
}
#endif /* INET6 */
@@ -686,9 +840,9 @@ ipsec6_getpolicybyaddr(m, dir, flag, error)
* other: failure, and set errno.
*/
int
-ipsec_setspidx_mbuf(spidx, dir, family, m, needport)
+ipsec_setspidx_mbuf(spidx, family, m, needport)
struct secpolicyindex *spidx;
- u_int dir, family;
+ int family;
struct mbuf *m;
int needport;
{
@@ -703,7 +857,6 @@ ipsec_setspidx_mbuf(spidx, dir, family, m, needport)
error = ipsec_setspidx(m, spidx, needport);
if (error)
goto bad;
- spidx->dir = dir;
return 0;
@@ -713,86 +866,6 @@ ipsec_setspidx_mbuf(spidx, dir, family, m, needport)
return EINVAL;
}
-static int
-ipsec4_setspidx_inpcb(m, pcb)
- struct mbuf *m;
- struct inpcb *pcb;
-{
- struct secpolicyindex *spidx;
- int error;
-
- /* sanity check */
- if (pcb == NULL)
- panic("ipsec4_setspidx_inpcb: no PCB found.");
- if (pcb->inp_sp == NULL)
- panic("ipsec4_setspidx_inpcb: no inp_sp found.");
- if (pcb->inp_sp->sp_out == NULL || pcb->inp_sp->sp_in == NULL)
- panic("ipsec4_setspidx_inpcb: no sp_in/out found.");
-
- bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx));
-
- spidx = &pcb->inp_sp->sp_in->spidx;
- error = ipsec_setspidx(m, spidx, 1);
- if (error)
- goto bad;
- spidx->dir = IPSEC_DIR_INBOUND;
-
- spidx = &pcb->inp_sp->sp_out->spidx;
- error = ipsec_setspidx(m, spidx, 1);
- if (error)
- goto bad;
- spidx->dir = IPSEC_DIR_OUTBOUND;
-
- return 0;
-
-bad:
- bzero(&pcb->inp_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->inp_sp->sp_out->spidx, sizeof(*spidx));
- return error;
-}
-
-#ifdef INET6
-static int
-ipsec6_setspidx_in6pcb(m, pcb)
- struct mbuf *m;
- struct in6pcb *pcb;
-{
- struct secpolicyindex *spidx;
- int error;
-
- /* sanity check */
- if (pcb == NULL)
- panic("ipsec6_setspidx_in6pcb: no PCB found.");
- if (pcb->in6p_sp == NULL)
- panic("ipsec6_setspidx_in6pcb: no in6p_sp found.");
- if (pcb->in6p_sp->sp_out == NULL || pcb->in6p_sp->sp_in == NULL)
- panic("ipsec6_setspidx_in6pcb: no sp_in/out found.");
-
- bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
-
- spidx = &pcb->in6p_sp->sp_in->spidx;
- error = ipsec_setspidx(m, spidx, 1);
- if (error)
- goto bad;
- spidx->dir = IPSEC_DIR_INBOUND;
-
- spidx = &pcb->in6p_sp->sp_out->spidx;
- error = ipsec_setspidx(m, spidx, 1);
- if (error)
- goto bad;
- spidx->dir = IPSEC_DIR_OUTBOUND;
-
- return 0;
-
-bad:
- bzero(&pcb->in6p_sp->sp_in->spidx, sizeof(*spidx));
- bzero(&pcb->in6p_sp->sp_out->spidx, sizeof(*spidx));
- return error;
-}
-#endif
-
/*
* configure security policy index (src/dst/proto/sport/dport)
* by looking at the content of mbuf.
@@ -814,6 +887,8 @@ ipsec_setspidx(m, spidx, needport)
if (m == NULL)
panic("ipsec_setspidx: m == 0 passed.");
+ bzero(spidx, sizeof(*spidx));
+
/*
* validate m->m_pkthdr.len. we see incorrect length if we
* mistakenly call this function with inconsistent mbuf chain
@@ -1000,6 +1075,7 @@ ipsec6_get_ulp(m, spidx, needport)
int off, nxt;
struct tcphdr th;
struct udphdr uh;
+ struct icmp6_hdr ih;
/* sanity check */
if (m == NULL)
@@ -1040,6 +1116,15 @@ ipsec6_get_ulp(m, spidx, needport)
((struct sockaddr_in6 *)&spidx->dst)->sin6_port = uh.uh_dport;
break;
case IPPROTO_ICMPV6:
+ spidx->ul_proto = nxt;
+ if (off + sizeof(struct icmp6_hdr) > m->m_pkthdr.len)
+ break;
+ m_copydata(m, off, sizeof(ih), (caddr_t)&ih);
+ ((struct sockaddr_in6 *)&spidx->src)->sin6_port =
+ htons((u_int16_t)ih.icmp6_type);
+ ((struct sockaddr_in6 *)&spidx->dst)->sin6_port =
+ htons((u_int16_t)ih.icmp6_code);
+ break;
default:
/* XXX intermediate headers??? */
spidx->ul_proto = nxt;
@@ -1068,22 +1153,14 @@ ipsec6_setspidx_ipaddr(m, spidx)
bzero(sin6, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
- bcopy(&ip6->ip6_src, &sin6->sin6_addr, sizeof(ip6->ip6_src));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
- }
+ in6_recoverscope(sin6, &ip6->ip6_src, NULL);
spidx->prefs = sizeof(struct in6_addr) << 3;
sin6 = (struct sockaddr_in6 *)&spidx->dst;
bzero(sin6, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
- bcopy(&ip6->ip6_dst, &sin6->sin6_addr, sizeof(ip6->ip6_dst));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
- }
+ in6_recoverscope(sin6, &ip6->ip6_dst, NULL);
spidx->prefd = sizeof(struct in6_addr) << 3;
return 0;
@@ -1109,19 +1186,47 @@ ipsec_delpcbpolicy(p)
/* initialize policy in PCB */
int
-ipsec_init_policy(so, pcb_sp)
+ipsec_init_pcbpolicy(so, pcb_sp)
struct socket *so;
struct inpcbpolicy **pcb_sp;
{
struct inpcbpolicy *new;
+ static int initialized = 0;
+ static struct secpolicy *in = NULL, *out = NULL;
/* sanity check. */
if (so == NULL || pcb_sp == NULL)
- panic("ipsec_init_policy: NULL pointer was passed.");
+ panic("ipsec_init_pcbpolicy: NULL pointer was passed.");
+
+ if (!initialized) {
+ if ((in = key_newsp(0)) == NULL)
+ return ENOBUFS;
+ if ((out = key_newsp(0)) == NULL) {
+ key_freesp(in);
+ in = NULL;
+ return ENOBUFS;
+ }
+
+ in->state = IPSEC_SPSTATE_ALIVE;
+ in->policy = IPSEC_POLICY_ENTRUST;
+ in->dir = IPSEC_DIR_INBOUND;
+ in->readonly = 1;
+ in->persist = 1;
+ in->so = NULL;
+
+ out->state = IPSEC_SPSTATE_ALIVE;
+ out->policy = IPSEC_POLICY_ENTRUST;
+ out->dir = IPSEC_DIR_OUTBOUND;
+ out->readonly = 1;
+ out->persist = 1;
+ out->so = NULL;
+
+ initialized++;
+ }
new = ipsec_newpcbpolicy();
if (new == NULL) {
- ipseclog((LOG_DEBUG, "ipsec_init_policy: No more memory.\n"));
+ ipseclog((LOG_DEBUG, "ipsec_init_pcbpolicy: No more memory.\n"));
return ENOBUFS;
}
bzero(new, sizeof(*new));
@@ -1131,20 +1236,10 @@ ipsec_init_policy(so, pcb_sp)
else
new->priv = 0;
- if ((new->sp_in = key_newsp()) == NULL) {
- ipsec_delpcbpolicy(new);
- return ENOBUFS;
- }
- new->sp_in->state = IPSEC_SPSTATE_ALIVE;
- new->sp_in->policy = IPSEC_POLICY_ENTRUST;
-
- if ((new->sp_out = key_newsp()) == NULL) {
- key_freesp(new->sp_in);
- ipsec_delpcbpolicy(new);
- return ENOBUFS;
- }
- new->sp_out->state = IPSEC_SPSTATE_ALIVE;
- new->sp_out->policy = IPSEC_POLICY_ENTRUST;
+ new->sp_in = in;
+ new->sp_in->refcnt++;
+ new->sp_out = out;
+ new->sp_out->refcnt++;
*pcb_sp = new;
@@ -1153,29 +1248,57 @@ ipsec_init_policy(so, pcb_sp)
/* copy old ipsec policy into new */
int
-ipsec_copy_policy(old, new)
+ipsec_copy_pcbpolicy(old, new)
struct inpcbpolicy *old, *new;
{
+
+ if (new->sp_in)
+ key_freesp(new->sp_in);
+ if (old->sp_in->policy == IPSEC_POLICY_IPSEC)
+ new->sp_in = ipsec_deepcopy_policy(old->sp_in);
+ else {
+ new->sp_in = old->sp_in;
+ new->sp_in->refcnt++;
+ }
+
+ if (new->sp_out)
+ key_freesp(new->sp_out);
+ if (old->sp_out->policy == IPSEC_POLICY_IPSEC)
+ new->sp_out = ipsec_deepcopy_policy(old->sp_out);
+ else {
+ new->sp_out = old->sp_out;
+ new->sp_out->refcnt++;
+ }
+
+ new->priv = old->priv;
+
+ return 0;
+}
+
+#if 0
+static int
+ipsec_deepcopy_pcbpolicy(pcb_sp)
+ struct inpcbpolicy *pcb_sp;
+{
struct secpolicy *sp;
- sp = ipsec_deepcopy_policy(old->sp_in);
+ sp = ipsec_deepcopy_policy(pcb_sp->sp_in);
if (sp) {
- key_freesp(new->sp_in);
- new->sp_in = sp;
+ key_freesp(pcb_sp->sp_in);
+ pcb_sp->sp_in = sp;
} else
return ENOBUFS;
- sp = ipsec_deepcopy_policy(old->sp_out);
+ sp = ipsec_deepcopy_policy(pcb_sp->sp_out);
if (sp) {
- key_freesp(new->sp_out);
- new->sp_out = sp;
+ key_freesp(pcb_sp->sp_out);
+ pcb_sp->sp_out = sp;
} else
return ENOBUFS;
- new->priv = old->priv;
-
return 0;
}
+#endif
/* deep-copy a policy in PCB */
static struct secpolicy *
@@ -1188,7 +1311,7 @@ ipsec_deepcopy_policy(src)
struct ipsecrequest *r;
struct secpolicy *dst;
- dst = key_newsp();
+ dst = key_newsp(0);
if (src == NULL || dst == NULL)
return NULL;
@@ -1219,9 +1342,15 @@ ipsec_deepcopy_policy(src)
q = &((*q)->next);
}
+ if (src->spidx)
+ if (keydb_setsecpolicyindex(dst, src->spidx) != 0)
+ goto fail;
+
dst->req = newchain;
dst->state = src->state;
dst->policy = src->policy;
+ dst->dir = src->dir;
+ dst->so = src->so;
/* do not touch the refcnt fields */
return dst;
@@ -1232,13 +1361,14 @@ fail:
free(p, M_SECA);
p = NULL;
}
+ key_freesp(dst);
return NULL;
}
/* set policy and ipsec request if present. */
static int
-ipsec_set_policy(pcb_sp, optname, request, len, priv)
- struct secpolicy **pcb_sp;
+ipsec_set_policy(spp, optname, request, len, priv)
+ struct secpolicy **spp;
int optname;
caddr_t request;
size_t len;
@@ -1249,7 +1379,7 @@ ipsec_set_policy(pcb_sp, optname, request, len, priv)
int error;
/* sanity check. */
- if (pcb_sp == NULL || *pcb_sp == NULL || request == NULL)
+ if (spp == NULL || *spp == NULL || request == NULL)
return EINVAL;
if (len < sizeof(*xpl))
return EINVAL;
@@ -1276,8 +1406,8 @@ ipsec_set_policy(pcb_sp, optname, request, len, priv)
newsp->state = IPSEC_SPSTATE_ALIVE;
/* clear old SP and set new SP */
- key_freesp(*pcb_sp);
- *pcb_sp = newsp;
+ key_freesp(*spp);
+ *spp = newsp;
KEYDEBUG(KEYDEBUG_IPSEC_DUMP,
printf("ipsec_set_policy: new policy\n");
kdebug_secpolicy(newsp));
@@ -1286,16 +1416,16 @@ ipsec_set_policy(pcb_sp, optname, request, len, priv)
}
static int
-ipsec_get_policy(pcb_sp, mp)
- struct secpolicy *pcb_sp;
+ipsec_get_policy(sp, mp)
+ struct secpolicy *sp;
struct mbuf **mp;
{
/* sanity check. */
- if (pcb_sp == NULL || mp == NULL)
+ if (sp == NULL || mp == NULL)
return EINVAL;
- *mp = key_sp2msg(pcb_sp);
+ *mp = key_sp2msg(sp);
if (!*mp) {
ipseclog((LOG_DEBUG, "ipsec_get_policy: No more memory.\n"));
return ENOBUFS;
@@ -1318,7 +1448,7 @@ ipsec4_set_policy(inp, optname, request, len, priv)
int priv;
{
struct sadb_x_policy *xpl;
- struct secpolicy **pcb_sp;
+ struct secpolicy **spp;
/* sanity check. */
if (inp == NULL || request == NULL)
@@ -1330,10 +1460,10 @@ ipsec4_set_policy(inp, optname, request, len, priv)
/* select direction */
switch (xpl->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
- pcb_sp = &inp->inp_sp->sp_in;
+ spp = &inp->inp_sp->sp_in;
break;
case IPSEC_DIR_OUTBOUND:
- pcb_sp = &inp->inp_sp->sp_out;
+ spp = &inp->inp_sp->sp_out;
break;
default:
ipseclog((LOG_ERR, "ipsec4_set_policy: invalid direction=%u\n",
@@ -1341,7 +1471,8 @@ ipsec4_set_policy(inp, optname, request, len, priv)
return EINVAL;
}
- return ipsec_set_policy(pcb_sp, optname, request, len, priv);
+ ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
+ return ipsec_set_policy(spp, optname, request, len, priv);
}
int
@@ -1352,7 +1483,7 @@ ipsec4_get_policy(inp, request, len, mp)
struct mbuf **mp;
{
struct sadb_x_policy *xpl;
- struct secpolicy *pcb_sp;
+ struct secpolicy *sp;
/* sanity check. */
if (inp == NULL || request == NULL || mp == NULL)
@@ -1366,10 +1497,10 @@ ipsec4_get_policy(inp, request, len, mp)
/* select direction */
switch (xpl->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
- pcb_sp = inp->inp_sp->sp_in;
+ sp = inp->inp_sp->sp_in;
break;
case IPSEC_DIR_OUTBOUND:
- pcb_sp = inp->inp_sp->sp_out;
+ sp = inp->inp_sp->sp_out;
break;
default:
ipseclog((LOG_ERR, "ipsec4_get_policy: invalid direction=%u\n",
@@ -1377,7 +1508,7 @@ ipsec4_get_policy(inp, request, len, mp)
return EINVAL;
}
- return ipsec_get_policy(pcb_sp, mp);
+ return ipsec_get_policy(sp, mp);
}
/* delete policy in PCB */
@@ -1402,6 +1533,8 @@ ipsec4_delete_pcbpolicy(inp)
inp->inp_sp->sp_out = NULL;
}
+ ipsec_invalpcbcache(inp->inp_sp, IPSEC_DIR_ANY);
+
ipsec_delpcbpolicy(inp->inp_sp);
inp->inp_sp = NULL;
@@ -1418,7 +1551,7 @@ ipsec6_set_policy(in6p, optname, request, len, priv)
int priv;
{
struct sadb_x_policy *xpl;
- struct secpolicy **pcb_sp;
+ struct secpolicy **spp;
/* sanity check. */
if (in6p == NULL || request == NULL)
@@ -1430,10 +1563,10 @@ ipsec6_set_policy(in6p, optname, request, len, priv)
/* select direction */
switch (xpl->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
- pcb_sp = &in6p->in6p_sp->sp_in;
+ spp = &in6p->in6p_sp->sp_in;
break;
case IPSEC_DIR_OUTBOUND:
- pcb_sp = &in6p->in6p_sp->sp_out;
+ spp = &in6p->in6p_sp->sp_out;
break;
default:
ipseclog((LOG_ERR, "ipsec6_set_policy: invalid direction=%u\n",
@@ -1441,7 +1574,8 @@ ipsec6_set_policy(in6p, optname, request, len, priv)
return EINVAL;
}
- return ipsec_set_policy(pcb_sp, optname, request, len, priv);
+ ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY);
+ return ipsec_set_policy(spp, optname, request, len, priv);
}
int
@@ -1452,7 +1586,7 @@ ipsec6_get_policy(in6p, request, len, mp)
struct mbuf **mp;
{
struct sadb_x_policy *xpl;
- struct secpolicy *pcb_sp;
+ struct secpolicy *sp;
/* sanity check. */
if (in6p == NULL || request == NULL || mp == NULL)
@@ -1466,10 +1600,10 @@ ipsec6_get_policy(in6p, request, len, mp)
/* select direction */
switch (xpl->sadb_x_policy_dir) {
case IPSEC_DIR_INBOUND:
- pcb_sp = in6p->in6p_sp->sp_in;
+ sp = in6p->in6p_sp->sp_in;
break;
case IPSEC_DIR_OUTBOUND:
- pcb_sp = in6p->in6p_sp->sp_out;
+ sp = in6p->in6p_sp->sp_out;
break;
default:
ipseclog((LOG_ERR, "ipsec6_get_policy: invalid direction=%u\n",
@@ -1477,7 +1611,7 @@ ipsec6_get_policy(in6p, request, len, mp)
return EINVAL;
}
- return ipsec_get_policy(pcb_sp, mp);
+ return ipsec_get_policy(sp, mp);
}
int
@@ -1501,6 +1635,8 @@ ipsec6_delete_pcbpolicy(in6p)
in6p->in6p_sp->sp_out = NULL;
}
+ ipsec_invalpcbcache(in6p->in6p_sp, IPSEC_DIR_ANY);
+
ipsec_delpcbpolicy(in6p->in6p_sp);
in6p->in6p_sp = NULL;
@@ -1513,8 +1649,9 @@ ipsec6_delete_pcbpolicy(in6p)
* Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned.
*/
u_int
-ipsec_get_reqlevel(isr)
+ipsec_get_reqlevel(isr, af)
struct ipsecrequest *isr;
+ int af;
{
u_int level = 0;
u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev;
@@ -1522,47 +1659,30 @@ ipsec_get_reqlevel(isr)
/* sanity check */
if (isr == NULL || isr->sp == NULL)
panic("ipsec_get_reqlevel: NULL pointer is passed.");
- if (((struct sockaddr *)&isr->sp->spidx.src)->sa_family
- != ((struct sockaddr *)&isr->sp->spidx.dst)->sa_family)
- panic("ipsec_get_reqlevel: family mismatched.");
-
-/* XXX note that we have ipseclog() expanded here - code sync issue */
-#define IPSEC_CHECK_DEFAULT(lev) \
- (((lev) != IPSEC_LEVEL_USE && (lev) != IPSEC_LEVEL_REQUIRE \
- && (lev) != IPSEC_LEVEL_UNIQUE) \
- ? (ipsec_debug \
- ? log(LOG_INFO, "fixed system default level " #lev ":%d->%d\n",\
- (lev), IPSEC_LEVEL_REQUIRE) \
- : 0), \
- (lev) = IPSEC_LEVEL_REQUIRE, \
- (lev) \
- : (lev))
/* set default level */
- switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) {
+ switch (af) {
#ifdef INET
case AF_INET:
- esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev);
- esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev);
- ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev);
- ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev);
+ esp_trans_deflev = ip4_esp_trans_deflev;
+ esp_net_deflev = ip4_esp_net_deflev;
+ ah_trans_deflev = ip4_ah_trans_deflev;
+ ah_net_deflev = ip4_ah_net_deflev;
break;
#endif
#ifdef INET6
case AF_INET6:
- esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev);
- esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev);
- ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev);
- ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev);
+ esp_trans_deflev = ip6_esp_trans_deflev;
+ esp_net_deflev = ip6_esp_net_deflev;
+ ah_trans_deflev = ip6_ah_trans_deflev;
+ ah_net_deflev = ip6_ah_net_deflev;
break;
#endif /* INET6 */
default:
panic("key_get_reqlevel: Unknown family. %d",
- ((struct sockaddr *)&isr->sp->spidx.src)->sa_family);
+ ((struct sockaddr *)&isr->sp->spidx->src)->sa_family);
}
-#undef IPSEC_CHECK_DEFAULT
-
/* set level */
switch (isr->level) {
case IPSEC_LEVEL_DEFAULT:
@@ -1587,7 +1707,7 @@ ipsec_get_reqlevel(isr)
break;
default:
panic("ipsec_get_reqlevel: "
- "Illegal protocol defined %u",
+ "Illegal protocol defined %u\n",
isr->saidx.proto);
}
break;
@@ -1640,7 +1760,7 @@ ipsec_in_reject(sp, m)
case IPSEC_POLICY_ENTRUST:
default:
- panic("ipsec_hdrsiz: Invalid policy found. %d", sp->policy);
+ panic("ipsec_in_reject: Invalid policy found. %d", sp->policy);
}
need_auth = 0;
@@ -1651,7 +1771,7 @@ ipsec_in_reject(sp, m)
for (isr = sp->req; isr != NULL; isr = isr->next) {
/* get current level */
- level = ipsec_get_reqlevel(isr);
+ level = ipsec_get_reqlevel(isr, AF_INET);
switch (isr->saidx.proto) {
case IPPROTO_ESP:
@@ -1698,9 +1818,9 @@ ipsec_in_reject(sp, m)
* and {ah,esp}4_input for tunnel mode
*/
int
-ipsec4_in_reject(m, inp)
+ipsec4_in_reject_so(m, so)
struct mbuf *m;
- struct inpcb *inp;
+ struct socket *so;
{
struct secpolicy *sp = NULL;
int error;
@@ -1714,11 +1834,11 @@ ipsec4_in_reject(m, inp)
* When we are called from ip_forward(), we call
* ipsec4_getpolicybyaddr() with IP_FORWARDING flag.
*/
- if (inp == NULL)
+ if (so == NULL)
sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
IP_FORWARDING, &error);
else
- sp = ipsec4_getpolicybypcb(m, IPSEC_DIR_INBOUND, inp, &error);
+ sp = ipsec4_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error);
/* XXX should be panic ? -> No, there may be error. */
if (sp == NULL)
@@ -1733,13 +1853,16 @@ ipsec4_in_reject(m, inp)
}
int
-ipsec4_in_reject_so(m, so)
+ipsec4_in_reject(m, inp)
struct mbuf *m;
- struct socket *so;
+ struct inpcb *inp;
{
- if (so == NULL)
- return ipsec4_in_reject(m, NULL);
- return ipsec4_in_reject(m, sotoinpcb(so));
+ if (inp == NULL)
+ return ipsec4_in_reject_so(m, NULL);
+ if (inp->inp_socket)
+ return ipsec4_in_reject_so(m, inp->inp_socket);
+ else
+ panic("ipsec4_in_reject: invalid inpcb/socket");
}
#ifdef INET6
@@ -1749,9 +1872,9 @@ ipsec4_in_reject_so(m, so)
* and {ah,esp}6_input for tunnel mode
*/
int
-ipsec6_in_reject(m, in6p)
+ipsec6_in_reject_so(m, so)
struct mbuf *m;
- struct in6pcb *in6p;
+ struct socket *so;
{
struct secpolicy *sp = NULL;
int error;
@@ -1765,31 +1888,34 @@ ipsec6_in_reject(m, in6p)
* When we are called from ip_forward(), we call
* ipsec6_getpolicybyaddr() with IP_FORWARDING flag.
*/
- if (in6p == NULL)
+ if (so == NULL)
sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND,
IP_FORWARDING, &error);
else
- sp = ipsec6_getpolicybypcb(m, IPSEC_DIR_INBOUND, in6p, &error);
+ sp = ipsec6_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error);
if (sp == NULL)
return 0; /* XXX should be panic ? */
result = ipsec_in_reject(sp, m);
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
- printf("DP ipsec6_in_reject call free SP:%p\n", sp));
+ printf("DP ipsec6_in_reject_so call free SP:%p\n", sp));
key_freesp(sp);
return result;
}
int
-ipsec6_in_reject_so(m, so)
+ipsec6_in_reject(m, in6p)
struct mbuf *m;
- struct socket *so;
+ struct in6pcb *in6p;
{
- if (so == NULL)
- return ipsec6_in_reject(m, NULL);
- return ipsec6_in_reject(m, sotoin6pcb(so));
+ if (in6p == NULL)
+ return ipsec6_in_reject_so(m, NULL);
+ if (in6p->in6p_socket)
+ return ipsec6_in_reject_so(m, in6p->in6p_socket);
+ else
+ panic("ipsec6_in_reject: invalid in6p/socket");
}
#endif
@@ -1883,11 +2009,8 @@ ipsec4_hdrsiz(m, dir, inp)
/* sanity check */
if (m == NULL)
return 0; /* XXX should be panic ? */
-#if 0
- /* this is possible in TIME_WAIT state */
if (inp != NULL && inp->inp_socket == NULL)
panic("ipsec4_hdrsize: why is socket NULL but there is PCB.");
-#endif
/* get SP for this packet.
* When we are called from ip_forward(), we call
@@ -1896,7 +2019,7 @@ ipsec4_hdrsiz(m, dir, inp)
if (inp == NULL)
sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error);
else
- sp = ipsec4_getpolicybypcb(m, dir, inp, &error);
+ sp = ipsec4_getpolicybysock(m, dir, inp->inp_socket, &error);
if (sp == NULL)
return 0; /* XXX should be panic ? */
@@ -1927,19 +2050,16 @@ ipsec6_hdrsiz(m, dir, in6p)
/* sanity check */
if (m == NULL)
- return 0; /* XXX shoud be panic ? */
-#if 0
- /* this is possible in TIME_WAIT state */
+ return 0; /* XXX should be panic ? */
if (in6p != NULL && in6p->in6p_socket == NULL)
panic("ipsec6_hdrsize: why is socket NULL but there is PCB.");
-#endif
/* get SP for this packet */
/* XXX Is it right to call with IP_FORWARDING. */
if (in6p == NULL)
sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error);
else
- sp = ipsec6_getpolicybypcb(m, dir, in6p, &error);
+ sp = ipsec6_getpolicybysock(m, dir, in6p->in6p_socket, &error);
if (sp == NULL)
return 0;
@@ -2147,10 +2267,10 @@ ipsec6_encapsulate(m, sav)
/* ip6->ip6_plen will be updated in ip6_output() */
}
ip6->ip6_nxt = IPPROTO_IPV6;
- bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.src)->sin6_addr,
- &ip6->ip6_src, sizeof(ip6->ip6_src));
- bcopy(&((struct sockaddr_in6 *)&sav->sah->saidx.dst)->sin6_addr,
- &ip6->ip6_dst, sizeof(ip6->ip6_dst));
+ in6_embedscope(&ip6->ip6_src,
+ (struct sockaddr_in6 *)&sav->sah->saidx.src, NULL, NULL);
+ in6_embedscope(&ip6->ip6_dst,
+ (struct sockaddr_in6 *)&sav->sah->saidx.dst, NULL, NULL);
ip6->ip6_hlim = IPV6_DEFHLIM;
/* XXX Should ip6_src be updated later ? */
@@ -2237,7 +2357,7 @@ ipsec_updatereplay(seq, sav)
struct secasvar *sav;
{
struct secreplay *replay;
- u_int32_t diff;
+ u_int64_t diff;
int fr;
u_int32_t wsizeb; /* constant: bits of window size */
int frlast; /* constant: last frame */
@@ -2306,7 +2426,7 @@ ipsec_updatereplay(seq, sav)
}
ok:
- if (replay->count == ~0) {
+ if (replay->count == 0xffffffff) {
/* set overflow flag */
replay->overflow++;
@@ -2344,7 +2464,7 @@ vshiftl(bitmap, nbit, wsize)
for (i = 1; i < wsize; i++) {
over = (bitmap[i] >> (8 - s));
bitmap[i] <<= s;
- bitmap[i-1] |= over;
+ bitmap[i - 1] |= over;
}
}
@@ -2477,6 +2597,37 @@ ipsec_dumpmbuf(m)
}
#ifdef INET
+static int
+ipsec4_checksa(isr, state)
+ struct ipsecrequest *isr;
+ struct ipsec_output_state *state;
+{
+ struct ip *ip;
+ struct secasindex saidx;
+ struct sockaddr_in *sin;
+
+ /* make SA index for search proper SA */
+ ip = mtod(state->m, struct ip *);
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ saidx.mode = isr->saidx.mode;
+ saidx.reqid = isr->saidx.reqid;
+ sin = (struct sockaddr_in *)&saidx.src;
+ if (sin->sin_len == 0) {
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = IPSEC_PORT_ANY;
+ bcopy(&ip->ip_src, &sin->sin_addr, sizeof(sin->sin_addr));
+ }
+ sin = (struct sockaddr_in *)&saidx.dst;
+ if (sin->sin_len == 0) {
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
+ sin->sin_port = IPSEC_PORT_ANY;
+ bcopy(&ip->ip_dst, &sin->sin_addr, sizeof(sin->sin_addr));
+ }
+
+ return key_checkrequest(isr, &saidx);
+}
/*
* IPsec output logic for IPv4.
*/
@@ -2488,11 +2639,9 @@ ipsec4_output(state, sp, flags)
{
struct ip *ip = NULL;
struct ipsecrequest *isr = NULL;
- struct secasindex saidx;
int s;
int error;
struct sockaddr_in *dst4;
- struct sockaddr_in *sin;
if (!state)
panic("state == NULL in ipsec4_output");
@@ -2502,6 +2651,7 @@ ipsec4_output(state, sp, flags)
panic("state->ro == NULL in ipsec4_output");
if (!state->dst)
panic("state->dst == NULL in ipsec4_output");
+ state->encap = 0;
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
printf("ipsec4_output: applyed SP\n");
@@ -2519,30 +2669,8 @@ ipsec4_output(state, sp, flags)
&& (flags & IP_FORWARDING))
continue;
#endif
-
- /* make SA index for search proper SA */
- ip = mtod(state->m, struct ip *);
- bcopy(&isr->saidx, &saidx, sizeof(saidx));
- saidx.mode = isr->saidx.mode;
- saidx.reqid = isr->saidx.reqid;
- sin = (struct sockaddr_in *)&saidx.src;
- if (sin->sin_len == 0) {
- sin->sin_len = sizeof(*sin);
- sin->sin_family = AF_INET;
- sin->sin_port = IPSEC_PORT_ANY;
- bcopy(&ip->ip_src, &sin->sin_addr,
- sizeof(sin->sin_addr));
- }
- sin = (struct sockaddr_in *)&saidx.dst;
- if (sin->sin_len == 0) {
- sin->sin_len = sizeof(*sin);
- sin->sin_family = AF_INET;
- sin->sin_port = IPSEC_PORT_ANY;
- bcopy(&ip->ip_dst, &sin->sin_addr,
- sizeof(sin->sin_addr));
- }
-
- if ((error = key_checkrequest(isr, &saidx)) != 0) {
+ error = ipsec4_checksa(isr, state);
+ if (error != 0) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2556,7 +2684,7 @@ ipsec4_output(state, sp, flags)
/* validity check */
if (isr->sav == NULL) {
- switch (ipsec_get_reqlevel(isr)) {
+ switch (ipsec_get_reqlevel(isr, AF_INET)) {
case IPSEC_LEVEL_USE:
continue;
case IPSEC_LEVEL_REQUIRE:
@@ -2639,6 +2767,8 @@ ipsec4_output(state, sp, flags)
state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
dst4 = (struct sockaddr_in *)state->dst;
}
+
+ state->encap++;
} else
splx(s);
@@ -2700,6 +2830,52 @@ bad:
#endif
#ifdef INET6
+static int
+ipsec6_checksa(isr, state, tunnel)
+ struct ipsecrequest *isr;
+ struct ipsec_output_state *state;
+ int tunnel;
+{
+ struct ip6_hdr *ip6;
+ struct secasindex saidx;
+ struct sockaddr_in6 *sin6;
+
+ if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
+#ifdef DIAGNOSTIC
+ if (!tunnel)
+ panic("ipsec6_checksa/inconsistent tunnel attribute");
+#endif
+ /* When tunnel mode, SA peers must be specified. */
+ return key_checkrequest(isr, &isr->saidx);
+ }
+
+ /* make SA index for search proper SA */
+ ip6 = mtod(state->m, struct ip6_hdr *);
+ if (tunnel) {
+ bzero(&saidx, sizeof(saidx));
+ saidx.proto = isr->saidx.proto;
+ } else
+ bcopy(&isr->saidx, &saidx, sizeof(saidx));
+ saidx.mode = isr->saidx.mode;
+ saidx.reqid = isr->saidx.reqid;
+ sin6 = (struct sockaddr_in6 *)&saidx.src;
+ if (sin6->sin6_len == 0 || tunnel) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ in6_recoverscope(sin6, &ip6->ip6_src, NULL);
+ }
+ sin6 = (struct sockaddr_in6 *)&saidx.dst;
+ if (sin6->sin6_len == 0 || tunnel) {
+ sin6->sin6_len = sizeof(*sin6);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = IPSEC_PORT_ANY;
+ in6_recoverscope(sin6, &ip6->ip6_dst, NULL);
+ }
+
+ return key_checkrequest(isr, &saidx);
+}
+
/*
* IPsec output logic for IPv6, transport mode.
*/
@@ -2714,10 +2890,8 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
{
struct ip6_hdr *ip6;
struct ipsecrequest *isr = NULL;
- struct secasindex saidx;
int error = 0;
int plen;
- struct sockaddr_in6 *sin6;
if (!state)
panic("state == NULL in ipsec6_output_trans");
@@ -2743,39 +2917,10 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
break;
}
- /* make SA index for search proper SA */
- ip6 = mtod(state->m, struct ip6_hdr *);
- 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) {
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = IPSEC_PORT_ANY;
- bcopy(&ip6->ip6_src, &sin6->sin6_addr,
- sizeof(ip6->ip6_src));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
- }
- }
- sin6 = (struct sockaddr_in6 *)&saidx.dst;
- if (sin6->sin6_len == 0) {
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = IPSEC_PORT_ANY;
- bcopy(&ip6->ip6_dst, &sin6->sin6_addr,
- sizeof(ip6->ip6_dst));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
- }
- }
-
- if (key_checkrequest(isr, &saidx) == ENOENT) {
+ error = ipsec6_checksa(isr, state, 0);
+ if (error == EIO)
+ goto bad;
+ if (error == ENOENT) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2784,7 +2929,6 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
* upper layer to retransmit the packet.
*/
ipsec6stat.out_nosa++;
- error = ENOENT;
/*
* Notify the fact that the packet is discarded
@@ -2793,7 +2937,12 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
* XXX: should we restrict the error to TCP packets?
* XXX: should we directly notify sockets via
* pfctlinputs?
+ *
+ * Noone have initialized rcvif until this point,
+ * so clear it.
*/
+ if ((state->m->m_flags & M_PKTHDR) != 0)
+ state->m->m_pkthdr.rcvif = NULL;
icmp6_error(state->m, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADMIN, 0);
state->m = NULL; /* icmp6_error freed the mbuf */
@@ -2802,7 +2951,7 @@ ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun)
/* validity check */
if (isr->sav == NULL) {
- switch (ipsec_get_reqlevel(isr)) {
+ switch (ipsec_get_reqlevel(isr, AF_INET6)) {
case IPSEC_LEVEL_USE:
continue;
case IPSEC_LEVEL_REQUIRE:
@@ -2884,10 +3033,9 @@ ipsec6_output_tunnel(state, sp, flags)
{
struct ip6_hdr *ip6;
struct ipsecrequest *isr = NULL;
- struct secasindex saidx;
int error = 0;
int plen;
- struct sockaddr_in6* dst6;
+ struct sockaddr_in6 *dst6;
int s;
if (!state)
@@ -2911,48 +3059,10 @@ ipsec6_output_tunnel(state, sp, flags)
}
for (/* already initialized */; isr; isr = isr->next) {
- if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
- /* When tunnel mode, SA peers must be specified. */
- bcopy(&isr->saidx, &saidx, sizeof(saidx));
- } else {
- /* make SA index to look for a proper SA */
- struct sockaddr_in6 *sin6;
-
- bzero(&saidx, sizeof(saidx));
- saidx.proto = isr->saidx.proto;
- saidx.mode = isr->saidx.mode;
- saidx.reqid = isr->saidx.reqid;
-
- ip6 = mtod(state->m, struct ip6_hdr *);
- sin6 = (struct sockaddr_in6 *)&saidx.src;
- if (sin6->sin6_len == 0) {
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = IPSEC_PORT_ANY;
- bcopy(&ip6->ip6_src, &sin6->sin6_addr,
- sizeof(ip6->ip6_src));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
- }
- }
- sin6 = (struct sockaddr_in6 *)&saidx.dst;
- if (sin6->sin6_len == 0) {
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_family = AF_INET6;
- sin6->sin6_port = IPSEC_PORT_ANY;
- bcopy(&ip6->ip6_dst, &sin6->sin6_addr,
- sizeof(ip6->ip6_dst));
- if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
- /* fix scope id for comparing SPD */
- sin6->sin6_addr.s6_addr16[1] = 0;
- sin6->sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
- }
- }
- }
-
- if (key_checkrequest(isr, &saidx) == ENOENT) {
+ error = ipsec6_checksa(isr, state, 1);
+ if (error == EIO)
+ goto bad;
+ if (error == ENOENT) {
/*
* IPsec processing is required, but no SA found.
* I assume that key_acquire() had been called
@@ -2967,7 +3077,7 @@ ipsec6_output_tunnel(state, sp, flags)
/* validity check */
if (isr->sav == NULL) {
- switch (ipsec_get_reqlevel(isr)) {
+ switch (ipsec_get_reqlevel(isr, AF_INET6)) {
case IPSEC_LEVEL_USE:
continue;
case IPSEC_LEVEL_REQUIRE:
@@ -3027,7 +3137,7 @@ ipsec6_output_tunnel(state, sp, flags)
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 ||
+ (!(state->ro->ro_rt->rt_flags & RTF_UP) ||
!IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr,
&ip6->ip6_dst))) {
RTFREE(state->ro->ro_rt);
@@ -3219,11 +3329,7 @@ ipsec4_tunnel_validate(m, off, nxt0, sav)
return 0;
oip = mtod(m, struct ip *);
-#ifdef _IP_VHL
- hlen = _IP_VHL_HL(oip->ip_vhl) << 2;
-#else
hlen = oip->ip_hl << 2;
-#endif
if (hlen != sizeof(struct ip))
return 0;
@@ -3273,6 +3379,14 @@ ipsec4_tunnel_validate(m, off, nxt0, sav)
sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
(struct sockaddr *)&isrc, (struct sockaddr *)&idst);
+ /*
+ * when there is no suitable inbound policy for the packet of the ipsec
+ * tunnel mode, the kernel never decapsulate the tunneled packet
+ * as the ipsec tunnel mode even when the system wide policy is "none".
+ * then the kernel leaves the generic tunnel module to process this
+ * packet. if there is no rule of the generic tunnel, the packet
+ * is rejected and the statistics will be counted up.
+ */
if (!sp)
return 0;
key_freesp(sp);
@@ -3308,6 +3422,7 @@ ipsec6_tunnel_validate(m, off, nxt0, sav)
return 0;
oip6 = mtod(m, struct ip6_hdr *);
+
/* AF_INET should be supported, but at this moment we don't. */
sin6 = (struct sockaddr_in6 *)&sav->sah->saidx.dst;
if (sin6->sin6_family != AF_INET6)
@@ -3338,14 +3453,6 @@ ipsec6_tunnel_validate(m, off, nxt0, sav)
sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst,
(struct sockaddr *)&isrc, (struct sockaddr *)&idst);
- /*
- * when there is no suitable inbound policy for the packet of the ipsec
- * tunnel mode, the kernel never decapsulate the tunneled packet
- * as the ipsec tunnel mode even when the system wide policy is "none".
- * then the kernel leaves the generic tunnel module to process this
- * packet. if there is no rule of the generic tunnel, the packet
- * is rejected and the statistics will be counted up.
- */
if (!sp)
return 0;
key_freesp(sp);
@@ -3374,8 +3481,7 @@ ipsec_copypkt(m)
* references to the cluster.
* XXX: is this approach effective?
*/
- if (n->m_ext.ext_type != EXT_CLUSTER ||
- MEXT_IS_REF(n)) {
+ if (!M_WRITABLE(n)) {
int remain, copied;
struct mbuf *mm;
@@ -3383,10 +3489,16 @@ ipsec_copypkt(m)
MGETHDR(mnew, M_DONTWAIT, MT_HEADER);
if (mnew == NULL)
goto fail;
- if (!m_dup_pkthdr(mnew, n, M_DONTWAIT)) {
- m_free(mnew);
- goto fail;
+ mnew->m_pkthdr = n->m_pkthdr;
+#if 0
+ /* XXX: convert to m_tag or delete? */
+ if (n->m_pkthdr.aux) {
+ mnew->m_pkthdr.aux =
+ m_copym(n->m_pkthdr.aux,
+ 0, M_COPYALL, M_DONTWAIT);
}
+#endif
+ M_MOVE_PKTHDR(mnew, n);
}
else {
MGET(mnew, M_DONTWAIT, MT_DATA);
@@ -3460,49 +3572,136 @@ ipsec_copypkt(m)
return (NULL);
}
+static struct ipsecaux *
+ipsec_addaux(m)
+ struct mbuf *m;
+{
+ struct m_tag *mtag;
+
+ mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL);
+ if (mtag == NULL) {
+ mtag = m_tag_get(PACKET_TAG_IPSEC_HISTORY,
+ sizeof(struct ipsecaux), M_NOWAIT);
+ if (mtag != NULL)
+ m_tag_prepend(m, mtag);
+ }
+ if (mtag == NULL)
+ return NULL; /* ENOBUFS */
+ /* XXX is this necessary? */
+ bzero((void *)(mtag + 1), sizeof(struct ipsecaux));
+ return mtag ? (struct ipsecaux *)(mtag + 1) : NULL;
+}
+
+static struct ipsecaux *
+ipsec_findaux(m)
+ struct mbuf *m;
+{
+ struct m_tag *mtag;
+
+ mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL);
+ return mtag ? (struct ipsecaux *)(mtag + 1) : NULL;
+}
+
void
ipsec_delaux(m)
struct mbuf *m;
{
struct m_tag *mtag;
- while ((mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL)) != NULL)
+ mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL);
+ if (mtag != NULL)
m_tag_delete(m, mtag);
}
+/* if the aux buffer is unnecessary, nuke it. */
+static void
+ipsec_optaux(m, aux)
+ struct mbuf *m;
+ struct ipsecaux *aux;
+{
+
+ if (aux == NULL)
+ return;
+ if (!aux->so && !aux->sp)
+ ipsec_delaux(m);
+}
+
+int
+ipsec_setsocket(m, so)
+ struct mbuf *m;
+ struct socket *so;
+{
+ struct ipsecaux *aux;
+
+ /* if so == NULL, don't insist on getting the aux mbuf */
+ if (so) {
+ aux = ipsec_addaux(m);
+ if (aux == NULL)
+ return ENOBUFS;
+ } else
+ aux = ipsec_findaux(m);
+ if (aux != NULL) {
+ aux->so = so;
+ }
+ ipsec_optaux(m, aux);
+ return 0;
+}
+
+struct socket *
+ipsec_getsocket(m)
+ struct mbuf *m;
+{
+ struct ipsecaux *aux;
+
+ aux = ipsec_findaux(m);
+ if (aux != NULL)
+ return aux->so;
+ else
+ return NULL;
+}
+
int
ipsec_addhist(m, proto, spi)
struct mbuf *m;
int proto;
u_int32_t spi;
{
- struct m_tag *mtag;
- struct ipsec_history *p;
+ struct ipsecaux *aux;
- mtag = m_tag_get(PACKET_TAG_IPSEC_HISTORY,
- sizeof (struct ipsec_history), M_NOWAIT);
- if (mtag == NULL)
+ aux = ipsec_addaux(m);
+ if (aux == NULL)
return ENOBUFS;
- p = (struct ipsec_history *)(mtag+1);
- bzero(p, sizeof(*p));
- p->ih_proto = proto;
- p->ih_spi = spi;
- m_tag_prepend(m, mtag);
+ aux->hdrs++;
return 0;
}
+int
+ipsec_getnhist(m)
+ struct mbuf *m;
+{
+ struct ipsecaux *aux;
+
+ aux = ipsec_findaux(m);
+ if (aux == NULL)
+ return 0;
+ return aux->hdrs;
+}
+
struct ipsec_history *
ipsec_gethist(m, lenp)
struct mbuf *m;
int *lenp;
{
- struct m_tag *mtag;
- mtag = m_tag_find(m, PACKET_TAG_IPSEC_HISTORY, NULL);
- if (mtag == NULL)
- return NULL;
- /* XXX NB: noone uses this so fake it */
- if (lenp)
- *lenp = sizeof (struct ipsec_history);
- return ((struct ipsec_history *)(mtag+1));
+ panic("ipsec_gethist: obsolete API");
+}
+
+void
+ipsec_clearhist(m)
+ struct mbuf *m;
+{
+ struct ipsecaux *aux;
+
+ aux = ipsec_findaux(m);
+ ipsec_optaux(m, aux);
}
diff --git a/sys/netinet6/ipsec.h b/sys/netinet6/ipsec.h
index 7787fab..356c985 100644
--- a/sys/netinet6/ipsec.h
+++ b/sys/netinet6/ipsec.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: ipsec.h,v 1.53 2001/11/20 08:32:38 itojun Exp $ */
+/* $KAME: ipsec.h,v 1.69 2003/09/10 23:49:11 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -54,7 +54,6 @@
* specifies ICMPv6 type, and the port field in "dst" specifies ICMPv6 code.
*/
struct secpolicyindex {
- u_int8_t dir; /* direction of packet flow, see blow */
struct sockaddr_storage src; /* IP src address for SP */
struct sockaddr_storage dst; /* IP dst address for SP */
u_int8_t prefs; /* prefix length in bits for src */
@@ -70,16 +69,26 @@ struct secpolicyindex {
/* Security Policy Data Base */
struct secpolicy {
- LIST_ENTRY(secpolicy) chain;
+ TAILQ_ENTRY(secpolicy) tailq; /* all SPD entries, both pcb/table */
+ LIST_ENTRY(secpolicy) chain; /* SPD entries on table */
+ u_int8_t dir; /* direction of packet flow */
+ int readonly; /* write prohibited */
+ int persist; /* will never be removed */
int refcnt; /* reference count */
- struct secpolicyindex spidx; /* selector */
- u_int32_t id; /* It's unique number on the system. */
+ struct secpolicyindex *spidx; /* selector - NULL if not valid */
+ u_int32_t id; /* it identifies a policy in the SPD. */
+#define IPSEC_MANUAL_POLICYID_MAX 0x3fff
+ /*
+ * 1 - 0x3fff are reserved for user operation.
+ * 0 are reserved. Others are for kernel use.
+ */
+ struct socket *so; /* backpointer to per-socket policy */
u_int state; /* 0: dead, others: alive */
#define IPSEC_SPSTATE_DEAD 0
#define IPSEC_SPSTATE_ALIVE 1
- u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */
+ int policy; /* DISCARD, NONE or IPSEC, see below */
struct ipsecrequest *req;
/* pointer to the ipsec request tree, */
/* if policy == IPSEC else this value == NULL.*/
@@ -98,6 +107,7 @@ struct secpolicy {
};
/* Request for IPsec */
+struct ifnet;
struct ipsecrequest {
struct ipsecrequest *next;
/* pointer to next structure */
@@ -108,6 +118,8 @@ struct ipsecrequest {
struct secasvar *sav; /* place holder of SA for use */
struct secpolicy *sp; /* back pointer to SP */
+
+ struct ifnet *tunifp; /* interface for tunnelling */
};
/* security policy in PCB */
@@ -115,6 +127,14 @@ struct inpcbpolicy {
struct secpolicy *sp_in;
struct secpolicy *sp_out;
int priv; /* privileged socket ? */
+
+ /* cached policy */
+ /* XXX 3 == IPSEC_DIR_MAX */
+ struct secpolicy *cache[3];
+ struct secpolicyindex cacheidx[3];
+ int cachegen[3]; /* cache generation #, the time we filled it */
+ int cacheflags;
+#define IPSEC_PCBSP_CONNECTED 1
};
/* SP acquiring list table. */
@@ -127,6 +147,14 @@ struct secspacq {
int count; /* for lifetime */
/* XXX: here is mbuf place holder to be sent ? */
};
+
+struct ipsecaux {
+ struct socket *so;
+ int hdrs; /* # of ipsec headers */
+
+ struct secpolicy *sp;
+ struct ipsecrequest *req;
+};
#endif /* _KERNEL */
/* according to IANA assignment, port 0x0000 and proto 0xff are reserved. */
@@ -210,6 +238,9 @@ struct ipsecstat {
u_quad_t out_esphist[256];
u_quad_t out_ahhist[256];
u_quad_t out_comphist[256];
+
+ u_quad_t spdcachelookup;
+ u_quad_t spdcachemiss;
};
/*
@@ -274,6 +305,7 @@ struct ipsec_output_state {
struct mbuf *m;
struct route *ro;
struct sockaddr *dst;
+ int encap;
};
struct ipsec_history {
@@ -283,8 +315,9 @@ struct ipsec_history {
extern int ipsec_debug;
+#ifdef INET
extern struct ipsecstat ipsecstat;
-extern struct secpolicy ip4_def_policy;
+extern struct secpolicy *ip4_def_policy;
extern int ip4_esp_trans_deflev;
extern int ip4_esp_net_deflev;
extern int ip4_ah_trans_deflev;
@@ -294,21 +327,26 @@ extern int ip4_ah_offsetmask;
extern int ip4_ipsec_dfbit;
extern int ip4_ipsec_ecn;
extern int ip4_esp_randpad;
+#endif
#define ipseclog(x) do { if (ipsec_debug) log x; } while (/*CONSTCOND*/ 0)
-struct inpcb;
-extern struct secpolicy *ipsec4_getpolicybypcb
- __P((struct mbuf *, u_int, struct inpcb *, int *));
+extern int ipsec_pcbconn __P((struct inpcbpolicy *));
+extern int ipsec_pcbdisconn __P((struct inpcbpolicy *));
+extern int ipsec_invalpcbcacheall __P((void));
+
extern struct secpolicy *ipsec4_getpolicybysock
__P((struct mbuf *, u_int, struct socket *, int *));
extern struct secpolicy *ipsec4_getpolicybyaddr
__P((struct mbuf *, u_int, int, int *));
+extern struct secpolicy *ipsec4_getpolicybytag
+ __P((struct mbuf *, u_int, int *));
-extern int ipsec_init_policy __P((struct socket *, struct inpcbpolicy **));
-extern int ipsec_copy_policy
+struct inpcb;
+extern int ipsec_init_pcbpolicy __P((struct socket *, struct inpcbpolicy **));
+extern int ipsec_copy_pcbpolicy
__P((struct inpcbpolicy *, struct inpcbpolicy *));
-extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *));
+extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *, int));
extern int ipsec4_set_policy __P((struct inpcb *, int, caddr_t, size_t, int));
extern int ipsec4_get_policy __P((struct inpcb *, caddr_t, size_t,
@@ -319,6 +357,7 @@ extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *));
struct secas;
struct tcpcb;
+struct tcp6cb;
extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *));
extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *));
@@ -337,8 +376,13 @@ extern int ipsec4_tunnel_validate __P((struct mbuf *, int, u_int,
struct secasvar *));
extern struct mbuf *ipsec_copypkt __P((struct mbuf *));
extern void ipsec_delaux __P((struct mbuf *));
+extern int ipsec_setsocket __P((struct mbuf *, struct socket *));
+extern struct socket *ipsec_getsocket __P((struct mbuf *));
extern int ipsec_addhist __P((struct mbuf *, int, u_int32_t));
+extern int ipsec_getnhist __P((struct mbuf *));
extern struct ipsec_history *ipsec_gethist __P((struct mbuf *, int *));
+extern void ipsec_clearhist __P((struct mbuf *));
+
#endif /* _KERNEL */
#ifndef _KERNEL
diff --git a/sys/netinet6/ipsec6.h b/sys/netinet6/ipsec6.h
index 1811088..e99dea3 100644
--- a/sys/netinet6/ipsec6.h
+++ b/sys/netinet6/ipsec6.h
@@ -42,7 +42,7 @@
#ifdef _KERNEL
extern struct ipsecstat ipsec6stat;
-extern struct secpolicy ip6_def_policy;
+extern struct secpolicy *ip6_def_policy;
extern int ip6_esp_trans_deflev;
extern int ip6_esp_net_deflev;
extern int ip6_ah_trans_deflev;
@@ -51,8 +51,6 @@ extern int ip6_ipsec_ecn;
extern int ip6_esp_randpad;
struct inpcb;
-extern struct secpolicy *ipsec6_getpolicybypcb
- __P((struct mbuf *, u_int, struct inpcb *, int *));
extern struct secpolicy *ipsec6_getpolicybysock
__P((struct mbuf *, u_int, struct socket *, int *));
extern struct secpolicy *ipsec6_getpolicybyaddr
@@ -60,10 +58,9 @@ extern struct secpolicy *ipsec6_getpolicybyaddr
extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *));
extern int ipsec6_delete_pcbpolicy __P((struct inpcb *));
-extern int ipsec6_set_policy __P((struct inpcb *inp, int optname,
- caddr_t request, size_t len, int priv));
-extern int ipsec6_get_policy
- __P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp));
+extern int ipsec6_set_policy __P((struct inpcb *, int, caddr_t, size_t, int));
+extern int ipsec6_get_policy __P((struct inpcb *, caddr_t, size_t,
+ struct mbuf **));
extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *));
struct tcp6cb;
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 97b57e1..192b4ea 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -1970,6 +1970,10 @@ nd6_output(ifp, origifp, m0, dst, rt0)
return (0);
sendpkt:
+#ifdef IPSEC
+ /* clean ipsec history once it goes out of the node */
+ ipsec_delaux(m);
+#endif
#ifdef MAC
mac_create_mbuf_linklayer(ifp, m);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 8a26928..fcda84f 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -487,6 +487,10 @@ nd6_ns_output(ifp, daddr6, taddr6, ln, dad)
nd_ns->nd_ns_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(*ip6), icmp6len);
+#ifdef IPSEC
+ /* Don't lookup socket */
+ (void)ipsec_setsocket(m, NULL);
+#endif
ip6_output(m, NULL, NULL, dad ? IPV6_DADOUTPUT : 0, &im6o, &outif, NULL);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
@@ -928,6 +932,10 @@ nd6_na_output(ifp, daddr6, taddr6, flags, tlladdr, sdl0)
nd_na->nd_na_cksum =
in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), icmp6len);
+#ifdef IPSEC
+ /* Don't lookup socket */
+ (void)ipsec_setsocket(m, NULL);
+#endif
ip6_output(m, NULL, NULL, 0, &im6o, &outif, NULL);
if (outif) {
icmp6_ifstat_inc(outif, ifs6_out_msg);
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 7525338..b714a2b 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -180,7 +180,7 @@ rip6_input(mp, offp, proto)
/*
* Check AH/ESP integrity.
*/
- if (n && ipsec6_in_reject(n, last)) {
+ if (n && ipsec6_in_reject_so(n, last->inp_socket)) {
m_freem(n);
ipsec6stat.in_polvio++;
/* do not inject data into pcb */
@@ -219,7 +219,7 @@ rip6_input(mp, offp, proto)
/*
* Check AH/ESP integrity.
*/
- if (last && ipsec6_in_reject(m, last)) {
+ if (last && ipsec6_in_reject_so(m, last->inp_socket)) {
m_freem(m);
ipsec6stat.in_polvio++;
ip6stat.ip6s_delivered--;
@@ -470,6 +470,13 @@ rip6_output(m, va_alist)
*p = in6_cksum(m, ip6->ip6_nxt, sizeof(*ip6), plen);
}
+#ifdef IPSEC
+ if (ipsec_setsocket(m, so) != 0) {
+ error = ENOBUFS;
+ goto bad;
+ }
+#endif /*IPSEC*/
+
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, 0,
in6p->in6p_moptions, &oifp, in6p);
if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
index f753a76..36a7fba 100644
--- a/sys/netinet6/udp6_output.c
+++ b/sys/netinet6/udp6_output.c
@@ -291,6 +291,12 @@ udp6_output(in6p, m, addr6, control, td)
flags = 0;
udp6stat.udp6s_opackets++;
+#ifdef IPSEC
+ if (ipsec_setsocket(m, in6p->in6p_socket) != 0) {
+ error = ENOBUFS;
+ goto release;
+ }
+#endif /* IPSEC */
error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
flags, in6p->in6p_moptions, NULL, in6p);
break;
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 93d7b1d..eb6bbac 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -261,7 +261,7 @@ udp6_input(mp, offp, proto)
/*
* Check AH/ESP integrity.
*/
- if (ipsec6_in_reject(m, last))
+ if (ipsec6_in_reject_so(m, last->inp_socket))
ipsec6stat.in_polvio++;
/* do not inject data into pcb */
else
@@ -327,7 +327,7 @@ udp6_input(mp, offp, proto)
/*
* Check AH/ESP integrity.
*/
- if (ipsec6_in_reject(m, last)) {
+ if (ipsec6_in_reject_so(m, last->inp_socket)) {
ipsec6stat.in_polvio++;
goto bad;
}
@@ -383,7 +383,7 @@ udp6_input(mp, offp, proto)
/*
* Check AH/ESP integrity.
*/
- if (ipsec6_in_reject(m, in6p)) {
+ if (ipsec6_in_reject_so(m, in6p->inp_socket)) {
ipsec6stat.in_polvio++;
goto bad;
}
diff --git a/sys/netkey/key.c b/sys/netkey/key.c
index c2cf71a..f24cff6 100644
--- a/sys/netkey/key.c
+++ b/sys/netkey/key.c
@@ -1,4 +1,4 @@
-/* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */
+/* $KAME: key.c,v 1.308 2003/09/07 20:35:59 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -131,7 +131,6 @@ u_int32_t key_debug_level = 0;
static u_int key_spi_trycnt = 1000;
static u_int32_t key_spi_minval = 0x100;
static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */
-static u_int32_t policy_id = 0;
static u_int key_int_random = 60; /*interval to initialize randseed,1(m)*/
static u_int key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/
static int key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/
@@ -141,10 +140,17 @@ static int key_preferred_oldsa = 1; /* preferred old sa rather than new sa.*/
static u_int32_t acq_seq = 0;
static int key_tick_init_random = 0;
-static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD */
+struct _satailq satailq; /* list of all SAD entry */
+struct _sptailq sptailq; /* SPD table + pcb */
+static LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD table */
static LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */
static LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1];
/* registed list */
+
+#define SPIHASHSIZE 128
+#define SPIHASH(x) (((x) ^ ((x) >> 16)) % SPIHASHSIZE)
+static LIST_HEAD(_spihash, secasvar) spihash[SPIHASHSIZE];
+
#ifndef IPSEC_NONBLOCK_ACQUIRE
static LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */
#endif
@@ -217,9 +223,7 @@ static int ipsec_esp_keymin = 256;
static int ipsec_esp_auth = 0;
static int ipsec_ah_keymin = 128;
-#ifdef SYSCTL_DECL
SYSCTL_DECL(_net_key);
-#endif
SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \
&key_debug_level, 0, "");
@@ -252,10 +256,6 @@ SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \
SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \
&key_blockacq_lifetime, 0, "");
-/* ESP auth */
-SYSCTL_INT(_net_key, KEYCTL_ESP_AUTH, esp_auth, CTLFLAG_RW, \
- &ipsec_esp_auth, 0, "");
-
/* minimum ESP key length */
SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \
&ipsec_esp_keymin, 0, "");
@@ -268,10 +268,6 @@ SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \
SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, preferred_oldsa, CTLFLAG_RW,\
&key_preferred_oldsa, 0, "");
-#ifndef LIST_FOREACH
-#define LIST_FOREACH(elm, head, field) \
- for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field))
-#endif
#define __LIST_CHAINED(elm) \
(!((elm)->chain.le_next == NULL && (elm)->chain.le_prev == NULL))
#define LIST_INSERT_TAIL(head, elm, type, field) \
@@ -308,7 +304,7 @@ do { \
#define KMALLOC(p, t, n) \
((p) = (t) malloc((unsigned long)(n), M_SECA, M_NOWAIT))
#define KFREE(p) \
- free((caddr_t)(p), M_SECA);
+ free((caddr_t)(p), M_SECA)
#else
#define KMALLOC(p, t, n) \
do { \
@@ -328,15 +324,14 @@ do { \
* set parameters into secpolicyindex buffer.
* Must allocate secpolicyindex buffer passed to this function.
*/
-#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) \
+#define KEY_SETSECSPIDX(s, d, ps, pd, ulp, idx) \
do { \
bzero((idx), sizeof(struct secpolicyindex)); \
- (idx)->dir = (_dir); \
(idx)->prefs = (ps); \
(idx)->prefd = (pd); \
(idx)->ul_proto = (ulp); \
- bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len); \
- bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len); \
+ bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \
+ bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \
} while (/*CONSTCOND*/ 0)
/*
@@ -349,8 +344,8 @@ do { \
(idx)->proto = (p); \
(idx)->mode = (m); \
(idx)->reqid = (r); \
- bcopy((s), &(idx)->src, ((const struct sockaddr *)(s))->sa_len); \
- bcopy((d), &(idx)->dst, ((const struct sockaddr *)(d))->sa_len); \
+ bcopy((s), &(idx)->src, ((struct sockaddr *)(s))->sa_len); \
+ bcopy((d), &(idx)->dst, ((struct sockaddr *)(d))->sa_len); \
} while (/*CONSTCOND*/ 0)
/* key statistics */
@@ -366,18 +361,16 @@ struct sadb_msghdr {
};
static struct secasvar *key_allocsa_policy(struct secasindex *);
-static void key_freesp_so(struct secpolicy **);
static struct secasvar *key_do_allocsa_policy(struct secashead *, u_int);
static void key_delsav(struct secasvar *);
static void key_delsp(struct secpolicy *);
-static struct secpolicy *key_getsp(struct secpolicyindex *);
+static struct secpolicy *key_getsp(struct secpolicyindex *, int);
static struct secpolicy *key_getspbyid(u_int32_t);
static u_int32_t key_newreqid(void);
static struct mbuf *key_gather_mbuf(struct mbuf *,
const struct sadb_msghdr *, int, int, ...);
static int key_spdadd(struct socket *, struct mbuf *,
const struct sadb_msghdr *);
-static u_int32_t key_getnewspid(void);
static int key_spddelete(struct socket *, struct mbuf *,
const struct sadb_msghdr *);
static int key_spddelete2(struct socket *, struct mbuf *,
@@ -398,6 +391,7 @@ static struct secasvar *key_newsav(struct mbuf *,
const struct sadb_msghdr *, struct secashead *, int *);
static struct secashead *key_getsah(struct secasindex *);
static struct secasvar *key_checkspidup(struct secasindex *, u_int32_t);
+static void key_setspi(struct secasvar *, u_int32_t);
static struct secasvar *key_getsavbyspi(struct secashead *, u_int32_t);
static int key_setsaval(struct secasvar *, struct mbuf *,
const struct sadb_msghdr *);
@@ -414,9 +408,12 @@ static struct mbuf *key_setsadbident(u_int16_t, u_int16_t, caddr_t,
int, u_int64_t);
#endif
static struct mbuf *key_setsadbxsa2(u_int8_t, u_int32_t, u_int32_t);
+static struct mbuf *key_setsadblifetime(u_int16_t, u_int32_t,
+ u_int64_t, u_int64_t, u_int64_t);
static struct mbuf *key_setsadbxpolicy(u_int16_t, u_int8_t,
u_int32_t);
static void *key_newbuf(const void *, u_int);
+static int key_ismyaddr(struct sockaddr *);
#ifdef INET6
static int key_ismyaddr6(struct sockaddr_in6 *);
#endif
@@ -424,18 +421,14 @@ static int key_ismyaddr6(struct sockaddr_in6 *);
/* flags for key_cmpsaidx() */
#define CMP_HEAD 1 /* protocol, addresses. */
#define CMP_MODE_REQID 2 /* additionally HEAD, reqid, mode. */
-#define CMP_REQID 3 /* additionally HEAD, reaid. */
+#define CMP_REQID 3 /* additionally HEAD, reqid. not used */
#define CMP_EXACTLY 4 /* all elements. */
-static int key_cmpsaidx
- (struct secasindex *, struct secasindex *, int);
+static int key_cmpsaidx(struct secasindex *, struct secasindex *, int);
-static int key_cmpspidx_exactly
- (struct secpolicyindex *, struct secpolicyindex *);
-static int key_cmpspidx_withmask
- (struct secpolicyindex *, struct secpolicyindex *);
static int key_sockaddrcmp(struct sockaddr *, struct sockaddr *, int);
static int key_bbcmp(caddr_t, caddr_t, u_int);
static void key_srandom(void);
+static u_long key_random(void);
static u_int16_t key_satype2proto(u_int8_t);
static u_int8_t key_proto2satype(u_int16_t);
@@ -487,13 +480,15 @@ static int key_dump(struct socket *, struct mbuf *,
static int key_promisc(struct socket *, struct mbuf *,
const struct sadb_msghdr *);
static int key_senderror(struct socket *, struct mbuf *, int);
-static int key_validate_ext(const struct sadb_ext *, int);
+static int key_validate_ext(struct sadb_ext *, int);
static int key_align(struct mbuf *, struct sadb_msghdr *);
#if 0
static const char *key_getfqdn(void);
static const char *key_getuserfqdn(void);
#endif
static void key_sa_chgstate(struct secasvar *, u_int8_t);
+static void key_sp_dead(struct secpolicy *);
+static void key_sp_unlink(struct secpolicy *);
static struct mbuf *key_alloc_mbuf(int);
/* %%% IPsec policy management */
@@ -504,18 +499,14 @@ static struct mbuf *key_alloc_mbuf(int);
* others: found and return the pointer.
*/
struct secpolicy *
-key_allocsp(spidx, dir)
+key_allocsp(tag, spidx, dir)
+ u_int16_t tag;
struct secpolicyindex *spidx;
u_int dir;
{
struct secpolicy *sp;
- struct timeval tv;
int s;
- /* sanity check */
- if (spidx == NULL)
- panic("key_allocsp: NULL pointer is passed.");
-
/* check direction */
switch (dir) {
case IPSEC_DIR_INBOUND:
@@ -527,19 +518,26 @@ key_allocsp(spidx, dir)
/* get a SP entry */
s = splnet(); /*called from softclock()*/
- KEYDEBUG(KEYDEBUG_IPSEC_DATA,
- printf("*** objects\n");
- kdebug_secpolicyindex(spidx));
-
- LIST_FOREACH(sp, &sptree[dir], chain) {
+ if (spidx) {
KEYDEBUG(KEYDEBUG_IPSEC_DATA,
- printf("*** in SPD\n");
- kdebug_secpolicyindex(&sp->spidx));
+ printf("*** objects\n");
+ kdebug_secpolicyindex(spidx));
+ }
+ LIST_FOREACH(sp, &sptree[dir], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
- if (key_cmpspidx_withmask(&sp->spidx, spidx))
- goto found;
+ if (sp->spidx) {
+ if (!spidx)
+ continue;
+
+ KEYDEBUG(KEYDEBUG_IPSEC_DATA,
+ printf("*** in SPD\n");
+ kdebug_secpolicyindex(sp->spidx));
+
+ if (key_cmpspidx_withmask(sp->spidx, spidx))
+ goto found;
+ }
}
splx(s);
@@ -547,11 +545,10 @@ key_allocsp(spidx, dir)
found:
/* sanity check */
- KEY_CHKSPDIR(sp->spidx.dir, dir, "key_allocsp");
+ KEY_CHKSPDIR(sp->dir, dir, "key_allocsp");
/* found a SPD entry */
- microtime(&tv);
- sp->lastused = tv.tv_sec;
+ sp->lastused = time_second;
sp->refcnt++;
splx(s);
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
@@ -571,7 +568,6 @@ key_gettunnel(osrc, odst, isrc, idst)
{
struct secpolicy *sp;
const int dir = IPSEC_DIR_INBOUND;
- struct timeval tv;
int s;
struct ipsecrequest *r1, *r2, *p;
struct sockaddr *os, *od, *is, *id;
@@ -597,15 +593,22 @@ key_gettunnel(osrc, odst, isrc, idst)
r2 = p;
if (!r1) {
- /* here we look at address matches only */
- spidx = sp->spidx;
- if (isrc->sa_len > sizeof(spidx.src) ||
- idst->sa_len > sizeof(spidx.dst))
- continue;
- bcopy(isrc, &spidx.src, isrc->sa_len);
- bcopy(idst, &spidx.dst, idst->sa_len);
- if (!key_cmpspidx_withmask(&sp->spidx, &spidx))
- continue;
+ if (sp->spidx) {
+ /*
+ * here we look at address matches
+ * only
+ */
+ spidx = *sp->spidx;
+ if (isrc->sa_len > sizeof(spidx.src) ||
+ idst->sa_len > sizeof(spidx.dst))
+ continue;
+ bcopy(isrc, &spidx.src, isrc->sa_len);
+ bcopy(idst, &spidx.dst, idst->sa_len);
+ if (!key_cmpspidx_withmask(sp->spidx,
+ &spidx))
+ continue;
+ } else
+ ; /* can't check for tagged policy */
} else {
is = (struct sockaddr *)&r1->saidx.src;
id = (struct sockaddr *)&r1->saidx.dst;
@@ -627,8 +630,7 @@ key_gettunnel(osrc, odst, isrc, idst)
return NULL;
found:
- microtime(&tv);
- sp->lastused = tv.tv_sec;
+ sp->lastused = time_second;
sp->refcnt++;
splx(s);
return sp;
@@ -663,7 +665,7 @@ key_checkrequest(isr, saidx)
}
/* get current level */
- level = ipsec_get_reqlevel(isr);
+ level = ipsec_get_reqlevel(isr, saidx->src.ss_family);
#if 0
/*
@@ -673,8 +675,8 @@ key_checkrequest(isr, saidx)
if (isr->sav != NULL) {
if (isr->sav->sah == NULL)
panic("key_checkrequest: sah is null.");
- if (isr->sav == (struct secasvar *)LIST_FIRST(
- &isr->sav->sah->savtree[SADB_SASTATE_DEAD])) {
+ if (isr->sav ==
+ LIST_FIRST(&isr->sav->sah->savtree[SADB_SASTATE_DEAD])) {
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP checkrequest calls free SA:%p\n",
isr->sav));
@@ -837,12 +839,13 @@ key_do_allocsa_policy(sah, state)
* permanent.
*/
if (d->lft_c->sadb_lifetime_addtime != 0) {
- struct mbuf *m, *result;
+ struct mbuf *m, *result = NULL;
key_sa_chgstate(d, SADB_SASTATE_DEAD);
m = key_setsadbmsg(SADB_DELETE, 0,
- d->sah->saidx.proto, 0, 0, d->refcnt - 1);
+ key_proto2satype(d->sah->saidx.proto),
+ 0, 0, d->refcnt - 1);
if (!m)
goto msgfail;
result = m;
@@ -850,17 +853,15 @@ key_do_allocsa_policy(sah, state)
/* set sadb_address for saidx's. */
m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
(struct sockaddr *)&d->sah->saidx.src,
- d->sah->saidx.src.ss_len << 3,
- IPSEC_ULPROTO_ANY);
+ FULLMASK, IPSEC_ULPROTO_ANY);
if (!m)
goto msgfail;
m_cat(result, m);
/* set sadb_address for saidx's. */
m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&d->sah->saidx.src,
- d->sah->saidx.src.ss_len << 3,
- IPSEC_ULPROTO_ANY);
+ (struct sockaddr *)&d->sah->saidx.dst,
+ FULLMASK, IPSEC_ULPROTO_ANY);
if (!m)
goto msgfail;
m_cat(result, m);
@@ -887,7 +888,12 @@ key_do_allocsa_policy(sah, state)
if (key_sendup_mbuf(NULL, result,
KEY_SENDUP_REGISTERED))
goto msgfail;
+
+ result = NULL;
+
msgfail:
+ if (result != NULL)
+ m_freem(result);
key_freesav(d);
}
}
@@ -923,9 +929,8 @@ key_allocsa(family, src, dst, proto, spi)
caddr_t src, dst;
u_int32_t spi;
{
- struct secashead *sah;
- struct secasvar *sav;
- u_int stateidx, state;
+ struct secasvar *sav, *match;
+ u_int stateidx, state, tmpidx, matchidx;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
int s;
@@ -955,114 +960,120 @@ key_allocsa(family, src, dst, proto, spi)
* encrypted so we can't check internal IP header.
*/
s = splnet(); /*called from softclock()*/
- LIST_FOREACH(sah, &sahtree, chain) {
- /*
- * search a valid state list for inbound packet.
- * the search order is not important.
- */
- for (stateidx = 0; stateidx < arraysize; stateidx++) {
+ /*
+ * search a valid state list for inbound packet.
+ * the search order is not important.
+ */
+ match = NULL;
+ matchidx = arraysize;
+ LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) {
+ if (sav->spi != spi)
+ continue;
+ if (proto != sav->sah->saidx.proto)
+ continue;
+ if (family != sav->sah->saidx.src.ss_family ||
+ family != sav->sah->saidx.dst.ss_family)
+ continue;
+ tmpidx = arraysize;
+ for (stateidx = 0; stateidx < matchidx; stateidx++) {
state = saorder_state_valid[stateidx];
- LIST_FOREACH(sav, &sah->savtree[state], chain) {
- /* sanity check */
- KEY_CHKSASTATE(sav->state, state, "key_allocsav");
- if (proto != sav->sah->saidx.proto)
- continue;
- if (spi != sav->spi)
- continue;
- if (family != sav->sah->saidx.src.ss_family ||
- family != sav->sah->saidx.dst.ss_family)
- continue;
+ if (sav->state == state) {
+ tmpidx = stateidx;
+ break;
+ }
+ }
+ if (tmpidx >= matchidx)
+ continue;
#if 0 /* don't check src */
- /* check src address */
- switch (family) {
- case AF_INET:
- bzero(&sin, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(sin);
- bcopy(src, &sin.sin_addr,
- sizeof(sin.sin_addr));
- if (key_sockaddrcmp((struct sockaddr*)&sin,
- (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
- continue;
+ /* check src address */
+ switch (family) {
+ case AF_INET:
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ bcopy(src, &sin.sin_addr,
+ sizeof(sin.sin_addr));
+ if (key_sockaddrcmp((struct sockaddr*)&sin,
+ (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
+ continue;
- break;
- case AF_INET6:
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(sin6);
- bcopy(src, &sin6.sin6_addr,
- sizeof(sin6.sin6_addr));
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
- /* kame fake scopeid */
- sin6.sin6_scope_id =
- ntohs(sin6.sin6_addr.s6_addr16[1]);
- sin6.sin6_addr.s6_addr16[1] = 0;
- }
- if (key_sockaddrcmp((struct sockaddr*)&sin6,
- (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
- continue;
- break;
- default:
- ipseclog((LOG_DEBUG, "key_allocsa: "
- "unknown address family=%d.\n",
- family));
- continue;
- }
+ break;
+ case AF_INET6:
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ bcopy(src, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
+ /* kame fake scopeid */
+ sin6.sin6_scope_id =
+ ntohs(sin6.sin6_addr.s6_addr16[1]);
+ sin6.sin6_addr.s6_addr16[1] = 0;
+ }
+ if (key_sockaddrcmp((struct sockaddr *)&sin6,
+ (struct sockaddr *)&sav->sah->saidx.src, 0) != 0)
+ continue;
+ break;
+ default:
+ ipseclog((LOG_DEBUG, "key_allocsa: "
+ "unknown address family=%d.\n",
+ family));
+ continue;
+ }
#endif
- /* check dst address */
- switch (family) {
- case AF_INET:
- bzero(&sin, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(sin);
- bcopy(dst, &sin.sin_addr,
- sizeof(sin.sin_addr));
- if (key_sockaddrcmp((struct sockaddr*)&sin,
- (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
- continue;
-
- break;
- case AF_INET6:
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(sin6);
- bcopy(dst, &sin6.sin6_addr,
- sizeof(sin6.sin6_addr));
- if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
- /* kame fake scopeid */
- sin6.sin6_scope_id =
- ntohs(sin6.sin6_addr.s6_addr16[1]);
- sin6.sin6_addr.s6_addr16[1] = 0;
- }
- if (key_sockaddrcmp((struct sockaddr*)&sin6,
- (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
- continue;
- break;
- default:
- ipseclog((LOG_DEBUG, "key_allocsa: "
- "unknown address family=%d.\n",
- family));
- continue;
- }
+ /* check dst address */
+ switch (family) {
+ case AF_INET:
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ bcopy(dst, &sin.sin_addr,
+ sizeof(sin.sin_addr));
+ if (key_sockaddrcmp((struct sockaddr*)&sin,
+ (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
+ continue;
- goto found;
+ break;
+ case AF_INET6:
+ bzero(&sin6, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(sin6);
+ bcopy(dst, &sin6.sin6_addr, sizeof(sin6.sin6_addr));
+ if (IN6_IS_SCOPE_LINKLOCAL(&sin6.sin6_addr)) {
+ /* kame fake scopeid */
+ sin6.sin6_scope_id =
+ ntohs(sin6.sin6_addr.s6_addr16[1]);
+ sin6.sin6_addr.s6_addr16[1] = 0;
}
+ if (key_sockaddrcmp((struct sockaddr *)&sin6,
+ (struct sockaddr *)&sav->sah->saidx.dst, 0) != 0)
+ continue;
+ break;
+ default:
+ ipseclog((LOG_DEBUG, "key_allocsa: "
+ "unknown address family=%d.\n", family));
+ continue;
}
+
+ match = sav;
+ matchidx = tmpidx;
}
+ if (match)
+ goto found;
+
/* not found */
splx(s);
return NULL;
found:
- sav->refcnt++;
+ match->refcnt++;
splx(s);
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP allocsa cause refcnt++:%d SA:%p\n",
- sav->refcnt, sav));
- return sav;
+ match->refcnt, match));
+ return match;
}
/*
@@ -1089,79 +1100,6 @@ key_freesp(sp)
}
/*
- * Must be called after calling key_allocsp().
- * For the packet with socket.
- */
-void
-key_freeso(so)
- struct socket *so;
-{
- /* sanity check */
- if (so == NULL)
- panic("key_freeso: NULL pointer is passed.");
-
- switch (so->so_proto->pr_domain->dom_family) {
-#ifdef INET
- case PF_INET:
- {
- struct inpcb *pcb = sotoinpcb(so);
-
- /* Does it have a PCB ? */
- if (pcb == NULL)
- return;
- key_freesp_so(&pcb->inp_sp->sp_in);
- key_freesp_so(&pcb->inp_sp->sp_out);
- }
- break;
-#endif
-#ifdef INET6
- case PF_INET6:
- {
- struct in6pcb *pcb = sotoin6pcb(so);
-
- /* Does it have a PCB ? */
- if (pcb == NULL)
- return;
- key_freesp_so(&pcb->in6p_sp->sp_in);
- key_freesp_so(&pcb->in6p_sp->sp_out);
- }
- break;
-#endif /* INET6 */
- default:
- ipseclog((LOG_DEBUG, "key_freeso: unknown address family=%d.\n",
- so->so_proto->pr_domain->dom_family));
- return;
- }
-
- return;
-}
-
-static void
-key_freesp_so(sp)
- struct secpolicy **sp;
-{
- /* sanity check */
- if (sp == NULL || *sp == NULL)
- panic("key_freesp_so: sp == NULL");
-
- switch ((*sp)->policy) {
- case IPSEC_POLICY_IPSEC:
- KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
- printf("DP freeso calls free SP:%p\n", *sp));
- key_freesp(*sp);
- *sp = NULL;
- break;
- case IPSEC_POLICY_ENTRUST:
- case IPSEC_POLICY_BYPASS:
- return;
- default:
- panic("key_freesp_so: Invalid policy found %d", (*sp)->policy);
- }
-
- return;
-}
-
-/*
* Must be called after calling key_allocsa().
* This function is called by key_freesp() to free some SA allocated
* for a policy.
@@ -1185,13 +1123,12 @@ key_freesav(sav)
key_delsav(sav);
}
-/*
- * free() SA variable entry.
- */
static void
key_delsav(sav)
struct secasvar *sav;
{
+ int s;
+
/* sanity check */
if (sav == NULL)
panic("key_delsav: NULL pointer is passed.");
@@ -1199,10 +1136,14 @@ key_delsav(sav)
if (sav->refcnt > 0)
panic("key_delsav: called with positive refcnt");
- /* remove from SA header */
+ s = splnet();
+
if (__LIST_CHAINED(sav))
LIST_REMOVE(sav, chain);
+ if (sav->spihash.le_prev || sav->spihash.le_next)
+ LIST_REMOVE(sav, spihash);
+
if (sav->key_auth != NULL) {
bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
KFREE(sav->key_auth);
@@ -1241,7 +1182,7 @@ key_delsav(sav)
keydb_delsecasvar(sav);
- return;
+ splx(s);
}
/* %%% SPD management */
@@ -1258,15 +1199,10 @@ key_delsp(sp)
if (sp == NULL)
panic("key_delsp: NULL pointer is passed.");
- sp->state = IPSEC_SPSTATE_DEAD;
-
if (sp->refcnt > 0)
panic("key_delsp: called with positive refcnt");
s = splnet(); /*called from softclock()*/
- /* remove from SP index */
- if (__LIST_CHAINED(sp))
- LIST_REMOVE(sp, chain);
{
struct ipsecrequest *isr = sp->req, *nextisr;
@@ -1299,8 +1235,9 @@ key_delsp(sp)
* others : found, pointer to a SP.
*/
static struct secpolicy *
-key_getsp(spidx)
+key_getsp(spidx, dir)
struct secpolicyindex *spidx;
+ int dir;
{
struct secpolicy *sp;
@@ -1308,10 +1245,12 @@ key_getsp(spidx)
if (spidx == NULL)
panic("key_getsp: NULL pointer is passed.");
- LIST_FOREACH(sp, &sptree[spidx->dir], chain) {
+ LIST_FOREACH(sp, &sptree[dir], chain) {
if (sp->state == IPSEC_SPSTATE_DEAD)
continue;
- if (key_cmpspidx_exactly(spidx, &sp->spidx)) {
+ if (!sp->spidx)
+ continue;
+ if (key_cmpspidx_exactly(spidx, sp->spidx)) {
sp->refcnt++;
return sp;
}
@@ -1331,18 +1270,7 @@ key_getspbyid(id)
{
struct secpolicy *sp;
- LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) {
- if (sp->state == IPSEC_SPSTATE_DEAD)
- continue;
- if (sp->id == id) {
- sp->refcnt++;
- return sp;
- }
- }
-
- LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) {
- if (sp->state == IPSEC_SPSTATE_DEAD)
- continue;
+ TAILQ_FOREACH(sp, &sptailq, tailq) {
if (sp->id == id) {
sp->refcnt++;
return sp;
@@ -1353,14 +1281,41 @@ key_getspbyid(id)
}
struct secpolicy *
-key_newsp()
+key_newsp(id)
+ u_int32_t id;
{
- struct secpolicy *newsp = NULL;
+ struct secpolicy *newsp = NULL, *sp;
+ u_int32_t newid;
+
+ if (id > IPSEC_MANUAL_POLICYID_MAX) {
+ ipseclog((LOG_DEBUG,
+ "key_newsp: policy_id=%u range "
+ "violation, updated by kernel.\n", id));
+ id = 0;
+ }
+
+ if (id == 0) {
+ if ((newid = keydb_newspid()) == 0) {
+ ipseclog((LOG_DEBUG,
+ "key_newsp: new policy_id allocation failed."));
+ return NULL;
+ }
+ } else {
+ sp = key_getspbyid(id);
+ if (sp != NULL) {
+ ipseclog((LOG_DEBUG,
+ "key_newsp: policy_id(%u) has been used.\n", id));
+ key_freesp(sp);
+ return NULL;
+ }
+ newid = id;
+ }
newsp = keydb_newsecpolicy();
if (!newsp)
return newsp;
+ newsp->id = newid;
newsp->refcnt = 1;
newsp->req = NULL;
@@ -1391,12 +1346,12 @@ key_msg2sp(xpl0, len, error)
return NULL;
}
- if ((newsp = key_newsp()) == NULL) {
+ if ((newsp = key_newsp(xpl0->sadb_x_policy_id)) == NULL) {
*error = ENOBUFS;
return NULL;
}
- newsp->spidx.dir = xpl0->sadb_x_policy_dir;
+ newsp->dir = xpl0->sadb_x_policy_dir;
newsp->policy = xpl0->sadb_x_policy_type;
/* check policy */
@@ -1638,7 +1593,7 @@ key_sp2msg(sp)
xpl->sadb_x_policy_len = PFKEY_UNIT64(tlen);
xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
xpl->sadb_x_policy_type = sp->policy;
- xpl->sadb_x_policy_dir = sp->spidx.dir;
+ xpl->sadb_x_policy_dir = sp->dir;
xpl->sadb_x_policy_id = sp->id;
p = (caddr_t)xpl + sizeof(*xpl);
@@ -1753,6 +1708,7 @@ key_gather_mbuf(m, mhp, ndeep, nitem, va_alist)
return result;
fail:
+ va_end(ap);
m_freem(result);
return NULL;
}
@@ -1779,26 +1735,34 @@ key_spdadd(so, m, mhp)
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
- struct sadb_address *src0, *dst0;
+ struct sadb_address *src0 = NULL, *dst0 = NULL;
struct sadb_x_policy *xpl0, *xpl;
struct sadb_lifetime *lft = NULL;
struct secpolicyindex spidx;
struct secpolicy *newsp;
- struct timeval tv;
+ struct ipsecrequest *isr;
int error;
+ int spidxmode;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
panic("key_spdadd: NULL pointer is passed.");
- if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL ||
- mhp->ext[SADB_EXT_ADDRESS_DST] == NULL ||
- mhp->ext[SADB_X_EXT_POLICY] == NULL) {
+ if (mhp->ext[SADB_EXT_ADDRESS_SRC] != NULL &&
+ mhp->ext[SADB_EXT_ADDRESS_DST] != NULL) {
+ ;
+ } else {
ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
}
- if (mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address) ||
- mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address) ||
+ if (mhp->ext[SADB_X_EXT_POLICY] == NULL) {
+ ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
+ return key_senderror(so, m, EINVAL);
+ }
+ if ((mhp->extlen[SADB_EXT_ADDRESS_SRC] &&
+ mhp->extlen[SADB_EXT_ADDRESS_SRC] < sizeof(struct sadb_address)) ||
+ (mhp->extlen[SADB_EXT_ADDRESS_DST] &&
+ mhp->extlen[SADB_EXT_ADDRESS_DST] < sizeof(struct sadb_address)) ||
mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
ipseclog((LOG_DEBUG, "key_spdadd: invalid message is passed.\n"));
return key_senderror(so, m, EINVAL);
@@ -1812,19 +1776,19 @@ key_spdadd(so, m, mhp)
lft = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_HARD];
}
- src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
- dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
- xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
+ /* spidx mode, or tag mode */
+ spidxmode = (mhp->ext[SADB_EXT_ADDRESS_SRC] != NULL);
- /* make secindex */
- /* XXX boundary check against sa_len */
- KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
- src0 + 1,
- dst0 + 1,
- src0->sadb_address_prefixlen,
- dst0->sadb_address_prefixlen,
- src0->sadb_address_proto,
- &spidx);
+ if (spidxmode) {
+ src0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_SRC];
+ dst0 = (struct sadb_address *)mhp->ext[SADB_EXT_ADDRESS_DST];
+ /* make secindex */
+ /* XXX boundary check against sa_len */
+ KEY_SETSECSPIDX(src0 + 1, dst0 + 1,
+ src0->sadb_address_prefixlen, dst0->sadb_address_prefixlen,
+ src0->sadb_address_proto, &spidx);
+ }
+ xpl0 = (struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY];
/* checking the direciton. */
switch (xpl0->sadb_x_policy_dir) {
@@ -1859,11 +1823,25 @@ key_spdadd(so, m, mhp)
* If the type is either SPDADD or SPDSETIDX AND a SP is found,
* then error.
*/
- newsp = key_getsp(&spidx);
+ if (xpl0->sadb_x_policy_id != 0)
+ newsp = key_getspbyid(xpl0->sadb_x_policy_id);
+ else if (spidxmode)
+ newsp = key_getsp(&spidx, xpl0->sadb_x_policy_dir);
+ else
+ newsp = NULL;
+
+ if (newsp && (newsp->readonly || newsp->persist)) {
+ ipseclog((LOG_DEBUG,
+ "key_spdadd: tried to alter readonly/persistent SP.\n"));
+ return key_senderror(so, m, EPERM);
+ }
+
if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
if (newsp) {
- newsp->state = IPSEC_SPSTATE_DEAD;
- key_freesp(newsp);
+ key_sp_dead(newsp);
+ key_freesp(newsp); /* ref gained by key_getsp */
+ key_sp_unlink(newsp);
+ newsp = NULL;
}
} else {
if (newsp != NULL) {
@@ -1878,71 +1856,117 @@ key_spdadd(so, m, mhp)
return key_senderror(so, m, error);
}
- if ((newsp->id = key_getnewspid()) == 0) {
- keydb_delsecpolicy(newsp);
- return key_senderror(so, m, ENOBUFS);
- }
-
- /* XXX boundary check against sa_len */
- KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
- src0 + 1,
- dst0 + 1,
- src0->sadb_address_prefixlen,
- dst0->sadb_address_prefixlen,
- src0->sadb_address_proto,
- &newsp->spidx);
+ if (spidxmode) {
+ error = keydb_setsecpolicyindex(newsp, &spidx);
+ if (error) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, error);
+ }
- /* sanity check on addr pair */
- if (((struct sockaddr *)(src0 + 1))->sa_family !=
- ((struct sockaddr *)(dst0+ 1))->sa_family) {
- keydb_delsecpolicy(newsp);
- return key_senderror(so, m, EINVAL);
- }
- if (((struct sockaddr *)(src0 + 1))->sa_len !=
- ((struct sockaddr *)(dst0+ 1))->sa_len) {
- keydb_delsecpolicy(newsp);
- return key_senderror(so, m, EINVAL);
- }
-#if 1
- if (newsp->req && newsp->req->saidx.src.ss_family) {
- struct sockaddr *sa;
- sa = (struct sockaddr *)(src0 + 1);
- if (sa->sa_family != newsp->req->saidx.src.ss_family) {
+ /* sanity check on addr pair */
+ if (((struct sockaddr *)(src0 + 1))->sa_family !=
+ ((struct sockaddr *)(dst0 + 1))->sa_family) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
- }
- if (newsp->req && newsp->req->saidx.dst.ss_family) {
- struct sockaddr *sa;
- sa = (struct sockaddr *)(dst0 + 1);
- if (sa->sa_family != newsp->req->saidx.dst.ss_family) {
+ if (((struct sockaddr *)(src0 + 1))->sa_len !=
+ ((struct sockaddr *)(dst0 + 1))->sa_len) {
keydb_delsecpolicy(newsp);
return key_senderror(so, m, EINVAL);
}
}
-#endif
- microtime(&tv);
- newsp->created = tv.tv_sec;
- newsp->lastused = tv.tv_sec;
+ for (isr = newsp->req; isr; isr = isr->next) {
+ struct sockaddr *sa;
+
+ /*
+ * port spec is not permitted for tunnel mode
+ */
+ if (isr->saidx.mode == IPSEC_MODE_TUNNEL && src0 && dst0) {
+ sa = (struct sockaddr *)(src0 + 1);
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)sa)->sin_port) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ break;
+ case AF_INET6:
+ if (((struct sockaddr_in6 *)sa)->sin6_port) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ sa = (struct sockaddr *)(dst0 + 1);
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (((struct sockaddr_in *)sa)->sin_port) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ break;
+ case AF_INET6:
+ if (((struct sockaddr_in6 *)sa)->sin6_port) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /*
+ * bark if we have different address family on tunnel address
+ * specification. applies only if we decapsulate in RFC2401
+ * IPsec (implementation limitation).
+ */
+ for (isr = newsp->req; isr; isr = isr->next) {
+ struct sockaddr *sa;
+
+ if (isr->saidx.src.ss_family && src0) {
+ sa = (struct sockaddr *)(src0 + 1);
+ if (sa->sa_family != isr->saidx.src.ss_family) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ }
+ if (isr->saidx.dst.ss_family && dst0) {
+ sa = (struct sockaddr *)(dst0 + 1);
+ if (sa->sa_family != isr->saidx.dst.ss_family) {
+ keydb_delsecpolicy(newsp);
+ return key_senderror(so, m, EINVAL);
+ }
+ }
+ }
+
+ newsp->created = time_second;
+ newsp->lastused = time_second;
newsp->lifetime = lft ? lft->sadb_lifetime_addtime : 0;
newsp->validtime = lft ? lft->sadb_lifetime_usetime : 0;
newsp->refcnt = 1; /* do not reclaim until I say I do */
newsp->state = IPSEC_SPSTATE_ALIVE;
- LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain);
+ LIST_INSERT_TAIL(&sptree[newsp->dir], newsp, secpolicy, chain);
/* delete the entry in spacqtree */
- if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) {
+ if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE &&
+ mhp->ext[SADB_EXT_ADDRESS_SRC]) {
struct secspacq *spacq;
if ((spacq = key_getspacq(&spidx)) != NULL) {
/* reset counter in order to deletion by timehandler. */
- microtime(&tv);
- spacq->created = tv.tv_sec;
+ spacq->created = time_second;
spacq->count = 0;
}
}
+ /* invalidate all cached SPD pointers on pcb */
+ ipsec_invalpcbcacheall();
+
{
struct mbuf *n, *mpolicy;
struct sadb_msg *newmsg;
@@ -1990,37 +2014,6 @@ key_spdadd(so, m, mhp)
}
/*
- * get new policy id.
- * OUT:
- * 0: failure.
- * others: success.
- */
-static u_int32_t
-key_getnewspid()
-{
- u_int32_t newid = 0;
- int count = key_spi_trycnt; /* XXX */
- struct secpolicy *sp;
-
- /* when requesting to allocate spi ranged */
- while (count--) {
- newid = (policy_id = (policy_id == ~0 ? 1 : policy_id + 1));
-
- if ((sp = key_getspbyid(newid)) == NULL)
- break;
-
- key_freesp(sp);
- }
-
- if (count == 0 || newid == 0) {
- ipseclog((LOG_DEBUG, "key_getnewspid: to allocate policy id is failed.\n"));
- return 0;
- }
-
- return newid;
-}
-
-/*
* SADB_SPDDELETE processing
* receive
* <base, address(SD), policy(*)>
@@ -2066,8 +2059,7 @@ key_spddelete(so, m, mhp)
/* make secindex */
/* XXX boundary check against sa_len */
- KEY_SETSECSPIDX(xpl0->sadb_x_policy_dir,
- src0 + 1,
+ KEY_SETSECSPIDX(src0 + 1,
dst0 + 1,
src0->sadb_address_prefixlen,
dst0->sadb_address_prefixlen,
@@ -2085,16 +2077,28 @@ key_spddelete(so, m, mhp)
}
/* Is there SP in SPD ? */
- if ((sp = key_getsp(&spidx)) == NULL) {
+ if ((sp = key_getsp(&spidx, xpl0->sadb_x_policy_dir)) == NULL) {
ipseclog((LOG_DEBUG, "key_spddelete: no SP found.\n"));
return key_senderror(so, m, EINVAL);
}
+ if (sp->persist) {
+ ipseclog((LOG_DEBUG,
+ "key_spddelete2: attempt to remove persistent SP:%u.\n",
+ sp->id));
+ return key_senderror(so, m, EPERM);
+ }
+
/* save policy id to be returned. */
xpl0->sadb_x_policy_id = sp->id;
- sp->state = IPSEC_SPSTATE_DEAD;
- key_freesp(sp);
+ key_sp_dead(sp);
+ key_freesp(sp); /* ref gained by key_getsp */
+ key_sp_unlink(sp);
+ sp = NULL;
+
+ /* invalidate all cached SPD pointers on pcb */
+ ipsec_invalpcbcacheall();
{
struct mbuf *n;
@@ -2123,7 +2127,7 @@ key_spddelete(so, m, mhp)
* and send,
* <base, policy(*)>
* to the ikmpd.
- * policy(*) including direction of policy.
+ * policy(*) including the policy id.
*
* m will always be freed.
*/
@@ -2143,8 +2147,7 @@ key_spddelete2(so, m, mhp)
if (mhp->ext[SADB_X_EXT_POLICY] == NULL ||
mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) {
ipseclog((LOG_DEBUG, "key_spddelete2: invalid message is passed.\n"));
- key_senderror(so, m, EINVAL);
- return 0;
+ return key_senderror(so, m, EINVAL);
}
id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id;
@@ -2153,11 +2156,23 @@ key_spddelete2(so, m, mhp)
if ((sp = key_getspbyid(id)) == NULL) {
ipseclog((LOG_DEBUG, "key_spddelete2: no SP found id:%u.\n",
id));
- key_senderror(so, m, EINVAL);
+ return key_senderror(so, m, EINVAL);
}
- sp->state = IPSEC_SPSTATE_DEAD;
- key_freesp(sp);
+ if (sp->persist) {
+ ipseclog((LOG_DEBUG,
+ "key_spddelete2: attempt to remove persistent SP:%u.\n",
+ id));
+ return key_senderror(so, m, EPERM);
+ }
+
+ key_sp_dead(sp);
+ key_freesp(sp); /* ref gained by key_getsp */
+ key_sp_unlink(sp);
+ sp = NULL;
+
+ /* invalidate all cached SPD pointers on pcb */
+ ipsec_invalpcbcacheall();
{
struct mbuf *n, *nn;
@@ -2213,7 +2228,7 @@ key_spddelete2(so, m, mhp)
}
/*
- * SADB_X_GET processing
+ * SADB_X_SPDGET processing
* receive
* <base, policy(*)>
* from the user(?),
@@ -2280,8 +2295,10 @@ key_spdacquire(sp)
struct secpolicy *sp;
{
struct mbuf *result = NULL, *m;
+#ifndef IPSEC_NONBLOCK_ACQUIRE
struct secspacq *newspacq;
- int error;
+#endif
+ int error = -1;
/* sanity check */
if (sp == NULL)
@@ -2290,9 +2307,14 @@ key_spdacquire(sp)
panic("key_spdacquire: called but there is request.");
if (sp->policy != IPSEC_POLICY_IPSEC)
panic("key_spdacquire: policy mismathed. IPsec is expected.");
+ if (!sp->spidx) {
+ error = EOPNOTSUPP;
+ goto fail;
+ }
+#ifndef IPSEC_NONBLOCK_ACQUIRE
/* get an entry to check whether sent message or not. */
- if ((newspacq = key_getspacq(&sp->spidx)) != NULL) {
+ if ((newspacq = key_getspacq(sp->spidx)) != NULL) {
if (key_blockacq_count < newspacq->count) {
/* reset counter and do send message. */
newspacq->count = 0;
@@ -2303,12 +2325,13 @@ key_spdacquire(sp)
}
} else {
/* make new entry for blocking to send SADB_ACQUIRE. */
- if ((newspacq = key_newspacq(&sp->spidx)) == NULL)
+ if ((newspacq = key_newspacq(sp->spidx)) == NULL)
return ENOBUFS;
/* add to acqtree */
LIST_INSERT_HEAD(&spacqtree, newspacq, chain);
}
+#endif
/* create new sadb_msg to reply. */
m = key_setsadbmsg(SADB_X_SPDACQUIRE, 0, 0, 0, 0, 0);
@@ -2318,6 +2341,16 @@ key_spdacquire(sp)
}
result = m;
+ /* set sadb_x_policy */
+ if (sp) {
+ m = key_setsadbxpolicy(sp->policy, sp->dir, sp->id);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
+ }
+
result->m_pkthdr.len = 0;
for (m = result; m; m = m->m_next)
result->m_pkthdr.len += m->m_len;
@@ -2325,7 +2358,7 @@ key_spdacquire(sp)
mtod(result, struct sadb_msg *)->sadb_msg_len =
PFKEY_UNIT64(result->m_pkthdr.len);
- return key_sendup_mbuf(NULL, m, KEY_SENDUP_REGISTERED);
+ return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED);
fail:
if (result)
@@ -2352,8 +2385,7 @@ key_spdflush(so, m, mhp)
const struct sadb_msghdr *mhp;
{
struct sadb_msg *newmsg;
- struct secpolicy *sp;
- u_int dir;
+ struct secpolicy *sp, *nextsp;
/* sanity check */
if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -2362,12 +2394,20 @@ key_spdflush(so, m, mhp)
if (m->m_len != PFKEY_ALIGN8(sizeof(struct sadb_msg)))
return key_senderror(so, m, EINVAL);
- for (dir = 0; dir < IPSEC_DIR_MAX; dir++) {
- LIST_FOREACH(sp, &sptree[dir], chain) {
- sp->state = IPSEC_SPSTATE_DEAD;
- }
+ for (sp = TAILQ_FIRST(&sptailq); sp; sp = nextsp) {
+ nextsp = TAILQ_NEXT(sp, tailq);
+ if (sp->persist)
+ continue;
+ if (sp->state == IPSEC_SPSTATE_DEAD)
+ continue;
+ key_sp_dead(sp);
+ key_sp_unlink(sp);
+ sp = NULL;
}
+ /* invalidate all cached SPD pointers on pcb */
+ ipsec_invalpcbcacheall();
+
if (sizeof(struct sadb_msg) > m->m_len + M_TRAILINGSPACE(m)) {
ipseclog((LOG_DEBUG, "key_spdflush: No more memory.\n"));
return key_senderror(so, m, ENOBUFS);
@@ -2449,21 +2489,35 @@ key_setdumpsp(sp, type, seq, pid)
goto fail;
result = m;
- m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&sp->spidx.src, sp->spidx.prefs,
- sp->spidx.ul_proto);
+ if (sp->spidx) {
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sp->spidx->src, sp->spidx->prefs,
+ sp->spidx->ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sp->spidx->dst, sp->spidx->prefd,
+ sp->spidx->ul_proto);
+ if (!m)
+ goto fail;
+ m_cat(result, m);
+ }
+
+ m = key_sp2msg(sp);
if (!m)
goto fail;
m_cat(result, m);
- m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&sp->spidx.dst, sp->spidx.prefd,
- sp->spidx.ul_proto);
+ m = key_setsadblifetime(SADB_EXT_LIFETIME_CURRENT,
+ 0, 0, (u_int64_t)sp->created, (u_int64_t)sp->lastused);
if (!m)
goto fail;
m_cat(result, m);
- m = key_sp2msg(sp);
+ m = key_setsadblifetime(SADB_EXT_LIFETIME_HARD,
+ 0, 0, (u_int64_t)sp->lifetime, (u_int64_t)sp->validtime);
if (!m)
goto fail;
m_cat(result, m);
@@ -2524,7 +2578,7 @@ key_getspreqmsglen(sp)
}
/*
- * SADB_SPDEXPIRE processing
+ * SADB_X_SPDEXPIRE processing
* send
* <base, address(SD), lifetime(CH), policy>
* to KMD by PF_KEY.
@@ -2584,24 +2638,26 @@ key_spdexpire(sp)
m_cat(result, m);
/* set sadb_address for source */
- m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
- (struct sockaddr *)&sp->spidx.src,
- sp->spidx.prefs, sp->spidx.ul_proto);
- if (!m) {
- error = ENOBUFS;
- goto fail;
- }
- m_cat(result, m);
+ if (sp->spidx) {
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC,
+ (struct sockaddr *)&sp->spidx->src,
+ sp->spidx->prefs, sp->spidx->ul_proto);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
- /* set sadb_address for destination */
- m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
- (struct sockaddr *)&sp->spidx.dst,
- sp->spidx.prefd, sp->spidx.ul_proto);
- if (!m) {
- error = ENOBUFS;
- goto fail;
+ /* set sadb_address for destination */
+ m = key_setsadbaddr(SADB_EXT_ADDRESS_DST,
+ (struct sockaddr *)&sp->spidx->dst,
+ sp->spidx->prefd, sp->spidx->ul_proto);
+ if (!m) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ m_cat(result, m);
}
- m_cat(result, m);
/* set secpolicy */
m = key_sp2msg(sp);
@@ -2693,7 +2749,7 @@ key_delsah(sah)
stateidx++) {
state = saorder_state_any[stateidx];
- for (sav = (struct secasvar *)LIST_FIRST(&sah->savtree[state]);
+ for (sav = LIST_FIRST(&sah->savtree[state]);
sav != NULL;
sav = nextsav) {
@@ -2772,7 +2828,7 @@ key_newsav(m, mhp, sah, errp)
switch (mhp->msg->sadb_msg_type) {
case SADB_GETSPI:
- newsav->spi = 0;
+ key_setspi(newsav, 0);
#ifdef IPSEC_DOSEQCHECK
/* sync sequence number */
@@ -2793,7 +2849,7 @@ key_newsav(m, mhp, sah, errp)
return NULL;
}
xsa = (const struct sadb_sa *)mhp->ext[SADB_EXT_SA];
- newsav->spi = xsa->sadb_sa_spi;
+ key_setspi(newsav, xsa->sadb_sa_spi);
newsav->seq = mhp->msg->sadb_msg_seq;
break;
default:
@@ -2812,11 +2868,7 @@ key_newsav(m, mhp, sah, errp)
}
/* reset created */
- {
- struct timeval tv;
- microtime(&tv);
- newsav->created = tv.tv_sec;
- }
+ newsav->created = time_second;
newsav->pid = mhp->msg->sadb_msg_pid;
@@ -2845,7 +2897,7 @@ key_getsah(saidx)
LIST_FOREACH(sah, &sahtree, chain) {
if (sah->state == SADB_SASTATE_DEAD)
continue;
- if (key_cmpsaidx(&sah->saidx, saidx, CMP_REQID))
+ if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID))
return sah;
}
@@ -2864,8 +2916,8 @@ key_checkspidup(saidx, spi)
struct secasindex *saidx;
u_int32_t spi;
{
- struct secashead *sah;
struct secasvar *sav;
+ u_int stateidx, state;
/* check address family */
if (saidx->src.ss_family != saidx->dst.ss_family) {
@@ -2874,17 +2926,37 @@ key_checkspidup(saidx, spi)
}
/* check all SAD */
- LIST_FOREACH(sah, &sahtree, chain) {
- if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst))
+ LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) {
+ if (sav->spi != spi)
continue;
- sav = key_getsavbyspi(sah, spi);
- if (sav != NULL)
- return sav;
+ for (stateidx = 0;
+ stateidx < _ARRAYLEN(saorder_state_alive);
+ stateidx++) {
+ state = saorder_state_alive[stateidx];
+ if (sav->state == state &&
+ key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst))
+ return sav;
+ }
}
return NULL;
}
+static void
+key_setspi(sav, spi)
+ struct secasvar *sav;
+ u_int32_t spi;
+{
+ int s;
+
+ s = splnet();
+ sav->spi = spi;
+ if (sav->spihash.le_prev || sav->spihash.le_next)
+ LIST_REMOVE(sav, spihash);
+ LIST_INSERT_HEAD(&spihash[SPIHASH(spi)], sav, spihash);
+ splx(s);
+}
+
/*
* search SAD litmited alive SA, protocol, SPI.
* OUT:
@@ -2896,31 +2968,27 @@ key_getsavbyspi(sah, spi)
struct secashead *sah;
u_int32_t spi;
{
- struct secasvar *sav;
- u_int stateidx, state;
-
- /* search all status */
- for (stateidx = 0;
- stateidx < _ARRAYLEN(saorder_state_alive);
- stateidx++) {
+ struct secasvar *sav, *match;
+ u_int stateidx, state, matchidx;
- state = saorder_state_alive[stateidx];
- LIST_FOREACH(sav, &sah->savtree[state], chain) {
-
- /* sanity check */
- if (sav->state != state) {
- ipseclog((LOG_DEBUG, "key_getsavbyspi: "
- "invalid sav->state (queue: %d SA: %d)\n",
- state, sav->state));
- continue;
+ match = NULL;
+ matchidx = _ARRAYLEN(saorder_state_alive);
+ LIST_FOREACH(sav, &spihash[SPIHASH(spi)], spihash) {
+ if (sav->spi != spi)
+ continue;
+ if (sav->sah != sah)
+ continue;
+ for (stateidx = 0; stateidx < matchidx; stateidx++) {
+ state = saorder_state_alive[stateidx];
+ if (sav->state == state) {
+ match = sav;
+ matchidx = stateidx;
+ break;
}
-
- if (sav->spi == spi)
- return sav;
}
}
- return NULL;
+ return match;
}
/*
@@ -2941,7 +3009,6 @@ key_setsaval(sav, m, mhp)
const struct esp_algorithm *algo;
#endif
int error = 0;
- struct timeval tv;
/* sanity check */
if (m == NULL || mhp == NULL || mhp->msg == NULL)
@@ -3096,8 +3163,7 @@ key_setsaval(sav, m, mhp)
}
/* reset created */
- microtime(&tv);
- sav->created = tv.tv_sec;
+ sav->created = time_second;
/* make lifetime for CURRENT */
KMALLOC(sav->lft_c, struct sadb_lifetime *,
@@ -3108,14 +3174,12 @@ key_setsaval(sav, m, mhp)
goto fail;
}
- microtime(&tv);
-
sav->lft_c->sadb_lifetime_len =
PFKEY_UNIT64(sizeof(struct sadb_lifetime));
sav->lft_c->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
sav->lft_c->sadb_lifetime_allocations = 0;
sav->lft_c->sadb_lifetime_bytes = 0;
- sav->lft_c->sadb_lifetime_addtime = tv.tv_sec;
+ sav->lft_c->sadb_lifetime_addtime = time_second;
sav->lft_c->sadb_lifetime_usetime = 0;
/* lifetimes for HARD and SOFT */
@@ -3135,7 +3199,12 @@ key_setsaval(sav, m, mhp)
error = ENOBUFS;
goto fail;
}
- /* to be initialize ? */
+ /* we no longer support byte lifetime */
+ if (sav->lft_h->sadb_lifetime_bytes) {
+ error = EINVAL;
+ goto fail;
+ }
+ /* initialize? */
}
lft0 = (struct sadb_lifetime *)mhp->ext[SADB_EXT_LIFETIME_SOFT];
@@ -3151,7 +3220,12 @@ key_setsaval(sav, m, mhp)
error = ENOBUFS;
goto fail;
}
- /* to be initialize ? */
+ /* we no longer support byte lifetime */
+ if (sav->lft_s->sadb_lifetime_bytes) {
+ error = EINVAL;
+ goto fail;
+ }
+ /* initialize? */
}
}
@@ -3164,14 +3238,17 @@ key_setsaval(sav, m, mhp)
sav->replay = NULL;
}
if (sav->key_auth != NULL) {
+ bzero(_KEYBUF(sav->key_auth), _KEYLEN(sav->key_auth));
KFREE(sav->key_auth);
sav->key_auth = NULL;
}
if (sav->key_enc != NULL) {
+ bzero(_KEYBUF(sav->key_enc), _KEYLEN(sav->key_enc));
KFREE(sav->key_enc);
sav->key_enc = NULL;
}
if (sav->sched) {
+ bzero(sav->sched, sav->schedlen);
KFREE(sav->sched);
sav->sched = NULL;
}
@@ -3411,7 +3488,7 @@ key_setdumpsa(sav, type, satype, seq, pid)
case SADB_X_EXT_SA2:
m = key_setsadbxsa2(sav->sah->saidx.mode,
- sav->replay ? sav->replay->count : 0,
+ sav->replay ? (sav->replay->count & 0xffffffff) : 0,
sav->sah->saidx.reqid);
if (!m)
goto fail;
@@ -3727,6 +3804,40 @@ key_setsadbxsa2(mode, seq, reqid)
}
/*
+ * set data into sadb_lifetime
+ */
+static struct mbuf *
+key_setsadblifetime(type, alloc, bytes, addtime, usetime)
+ u_int16_t type;
+ u_int32_t alloc;
+ u_int64_t bytes, addtime, usetime;
+{
+ struct mbuf *m;
+ struct sadb_lifetime *p;
+ size_t len;
+
+ len = PFKEY_ALIGN8(sizeof(struct sadb_lifetime));
+ m = key_alloc_mbuf(len);
+ if (!m || m->m_next) { /*XXX*/
+ if (m)
+ m_freem(m);
+ return NULL;
+ }
+
+ p = mtod(m, struct sadb_lifetime *);
+
+ bzero(p, len);
+ p->sadb_lifetime_len = PFKEY_UNIT64(len);
+ p->sadb_lifetime_exttype = type;
+ p->sadb_lifetime_allocations = alloc;
+ p->sadb_lifetime_bytes = bytes;
+ p->sadb_lifetime_addtime = addtime;
+ p->sadb_lifetime_usetime = usetime;
+
+ return m;
+}
+
+/*
* set data into sadb_x_policy
*/
static struct mbuf *
@@ -3784,7 +3895,7 @@ key_newbuf(src, len)
* OUT: 1: true, i.e. my address.
* 0: false
*/
-int
+static int
key_ismyaddr(sa)
struct sockaddr *sa;
{
@@ -3846,7 +3957,6 @@ key_ismyaddr6(sin6)
* XXX Multicast
* XXX why do we care about multlicast here while we don't care
* about IPv4 multicast??
- * XXX scope
*/
in6m = NULL;
IN6_LOOKUP_MULTI(sin6->sin6_addr, ia->ia_ifp, in6m);
@@ -3899,8 +4009,8 @@ key_cmpsaidx(saidx0, saidx1, flag)
return 0;
} else {
- /* CMP_MODE_REQID, CMP_REQID, CMP_HEAD */
- if (flag == CMP_MODE_REQID || flag == CMP_REQID) {
+ /* CMP_MODE_REQID, CMP_HEAD */
+ if (flag == CMP_MODE_REQID) {
/*
* If reqid of SPD is non-zero, unique SA is required.
* The result must be of same reqid in this case.
@@ -3937,7 +4047,7 @@ key_cmpsaidx(saidx0, saidx1, flag)
* 1 : equal
* 0 : not equal
*/
-static int
+int
key_cmpspidx_exactly(spidx0, spidx1)
struct secpolicyindex *spidx0, *spidx1;
{
@@ -3973,7 +4083,7 @@ key_cmpspidx_exactly(spidx0, spidx1)
* 1 : equal
* 0 : not equal
*/
-static int
+int
key_cmpspidx_withmask(spidx0, spidx1)
struct secpolicyindex *spidx0, *spidx1;
{
@@ -4160,7 +4270,8 @@ key_bbcmp(p1, p2, bits)
* XXX: year 2038 problem may remain.
*/
void
-key_timehandler(void)
+key_timehandler(arg)
+ void *arg;
{
u_int dir;
int s;
@@ -4181,7 +4292,8 @@ key_timehandler(void)
nextsp = LIST_NEXT(sp, chain);
if (sp->state == IPSEC_SPSTATE_DEAD) {
- key_freesp(sp);
+ key_sp_unlink(sp); /*XXX*/
+ sp = NULL;
continue;
}
@@ -4193,7 +4305,7 @@ key_timehandler(void)
tv.tv_sec - sp->created > sp->lifetime) ||
(sp->validtime &&
tv.tv_sec - sp->lastused > sp->validtime)) {
- sp->state = IPSEC_SPSTATE_DEAD;
+ key_sp_dead(sp);
key_spdexpire(sp);
continue;
}
@@ -4412,10 +4524,11 @@ key_timehandler(void)
key_srandom();
}
-#ifndef IPSEC_DEBUG2
- /* do exchange to tick time !! */
- (void)timeout((void *)key_timehandler, (void *)0, hz);
-#endif /* IPSEC_DEBUG2 */
+ /*
+ * should set timeout based on the most closest timer expiration.
+ * we don't bother to do that yet.
+ */
+ (void)timeout(key_timehandler, (void *)0, hz);
splx(s);
return;
@@ -4430,7 +4543,7 @@ key_srandom()
return;
}
-u_long
+static u_long
key_random()
{
u_long value;
@@ -4635,7 +4748,7 @@ key_getspi(so, m, mhp)
}
/* set spi */
- newsav->spi = htonl(spi);
+ key_setspi(newsav, htonl(spi));
#ifndef IPSEC_NONBLOCK_ACQUIRE
/* delete the entry in acqtree */
@@ -4643,9 +4756,7 @@ key_getspi(so, m, mhp)
struct secacq *acq;
if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) {
/* reset counter in order to deletion by timehandler. */
- struct timeval tv;
- microtime(&tv);
- acq->created = tv.tv_sec;
+ acq->created = time_second;
acq->count = 0;
}
}
@@ -5513,9 +5624,9 @@ key_getcomb_setlifetime(comb)
comb->sadb_comb_soft_bytes = 0;
comb->sadb_comb_hard_bytes = 0;
comb->sadb_comb_hard_addtime = 86400; /* 1 day */
- comb->sadb_comb_soft_addtime = comb->sadb_comb_soft_addtime * 80 / 100;
- comb->sadb_comb_soft_usetime = 28800; /* 8 hours */
- comb->sadb_comb_hard_usetime = comb->sadb_comb_hard_usetime * 80 / 100;
+ comb->sadb_comb_soft_addtime = comb->sadb_comb_hard_addtime * 80 / 100;
+ comb->sadb_comb_hard_usetime = 28800; /* 8 hours */
+ comb->sadb_comb_soft_usetime = comb->sadb_comb_hard_usetime * 80 / 100;
}
#ifdef IPSEC_ESP
@@ -5854,7 +5965,7 @@ key_acquire(saidx, sp)
/* set sadb_x_policy */
if (sp) {
- m = key_setsadbxpolicy(sp->policy, sp->spidx.dir, sp->id);
+ m = key_setsadbxpolicy(sp->policy, sp->dir, sp->id);
if (!m) {
error = ENOBUFS;
goto fail;
@@ -5960,7 +6071,6 @@ key_newacq(saidx)
struct secasindex *saidx;
{
struct secacq *newacq;
- struct timeval tv;
/* get new entry */
KMALLOC(newacq, struct secacq *, sizeof(struct secacq));
@@ -5973,8 +6083,7 @@ key_newacq(saidx)
/* copy secindex */
bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx));
newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq);
- microtime(&tv);
- newacq->created = tv.tv_sec;
+ newacq->created = time_second;
newacq->count = 0;
return newacq;
@@ -6014,7 +6123,9 @@ key_newspacq(spidx)
struct secpolicyindex *spidx;
{
struct secspacq *acq;
- struct timeval tv;
+
+ if (!spidx)
+ return NULL;
/* get new entry */
KMALLOC(acq, struct secspacq *, sizeof(struct secspacq));
@@ -6026,9 +6137,8 @@ key_newspacq(spidx)
/* copy secindex */
bcopy(spidx, &acq->spidx, sizeof(acq->spidx));
- microtime(&tv);
- acq->created = tv.tv_sec;
- acq->count = 0;
+ acq->created = time_second;
+ acq->count = 1;
return acq;
}
@@ -6039,6 +6149,9 @@ key_getspacq(spidx)
{
struct secspacq *acq;
+ if (!spidx)
+ return NULL;
+
LIST_FOREACH(acq, &spacqtree, chain) {
if (key_cmpspidx_exactly(spidx, &acq->spidx))
return acq;
@@ -6067,7 +6180,7 @@ key_acquire2(so, m, mhp)
struct mbuf *m;
const struct sadb_msghdr *mhp;
{
- const struct sadb_address *src0, *dst0;
+ struct sadb_address *src0, *dst0;
struct secasindex saidx;
struct secashead *sah;
u_int16_t proto;
@@ -6086,7 +6199,6 @@ key_acquire2(so, m, mhp)
if (mhp->msg->sadb_msg_len == PFKEY_UNIT64(sizeof(struct sadb_msg))) {
#ifndef IPSEC_NONBLOCK_ACQUIRE
struct secacq *acq;
- struct timeval tv;
/* check sequence number */
if (mhp->msg->sadb_msg_seq == 0) {
@@ -6105,8 +6217,7 @@ key_acquire2(so, m, mhp)
}
/* reset acq counter in order to deletion by timehander. */
- microtime(&tv);
- acq->created = tv.tv_sec;
+ acq->created = time_second;
acq->count = 0;
#endif
m_freem(m);
@@ -6422,7 +6533,7 @@ key_expire(sav)
/* create SA extension */
m = key_setsadbxsa2(sav->sah->saidx.mode,
- sav->replay ? sav->replay->count : 0,
+ sav->replay ? (sav->replay->count & 0xffffffff) : 0,
sav->sah->saidx.reqid);
if (!m) {
error = ENOBUFS;
@@ -6604,7 +6715,6 @@ key_dump(so, m, mhp)
u_int8_t satype;
u_int8_t state;
int cnt;
- struct sadb_msg *newmsg;
struct mbuf *n;
/* sanity check */
@@ -6638,7 +6748,6 @@ key_dump(so, m, mhp)
return key_senderror(so, m, ENOENT);
/* send this to the userland, one at a time. */
- newmsg = NULL;
LIST_FOREACH(sah, &sahtree, chain) {
if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC &&
proto != sah->saidx.proto)
@@ -7143,12 +7252,12 @@ key_align(m, mhp)
static int
key_validate_ext(ext, len)
- const struct sadb_ext *ext;
+ struct sadb_ext *ext;
int len;
{
- const struct sockaddr *sa;
+ struct sockaddr *sa;
enum { NONE, ADDR } checktype = NONE;
- int baselen;
+ int baselen = 0;
const int sal = offsetof(struct sockaddr, sa_len) + sizeof(sa->sa_len);
if (len != PFKEY_UNUNIT64(ext->sadb_ext_len))
@@ -7173,17 +7282,14 @@ key_validate_ext(ext, len)
break;
case SADB_EXT_IDENTITY_SRC:
case SADB_EXT_IDENTITY_DST:
- if (((const struct sadb_ident *)ext)->sadb_ident_type ==
+ if (((struct sadb_ident *)ext)->sadb_ident_type ==
SADB_X_IDENTTYPE_ADDR) {
baselen = PFKEY_ALIGN8(sizeof(struct sadb_ident));
checktype = ADDR;
- } else {
- baselen = 0; /* XXX pacify gcc-3.1 */
+ } else
checktype = NONE;
- }
break;
default:
- baselen = 0; /* XXX pacify gcc-3.1 */
checktype = NONE;
break;
}
@@ -7192,7 +7298,7 @@ key_validate_ext(ext, len)
case NONE:
break;
case ADDR:
- sa = (struct sockaddr *)((uintptr_t)ext + baselen);
+ sa = (struct sockaddr *)((caddr_t)ext + baselen);
if (len < baselen + sal)
return EINVAL;
if (baselen + PFKEY_ALIGN8(sa->sa_len) != len)
@@ -7218,24 +7324,40 @@ key_init()
for (i = 0; i <= SADB_SATYPE_MAX; i++)
LIST_INIT(&regtree[i]);
+ for (i = 0; i < SPIHASHSIZE; i++)
+ LIST_INIT(&spihash[i]);
+
#ifndef IPSEC_NONBLOCK_ACQUIRE
LIST_INIT(&acqtree);
#endif
LIST_INIT(&spacqtree);
+ TAILQ_INIT(&satailq);
+ TAILQ_INIT(&sptailq);
+
/* system default */
#ifdef INET
- ip4_def_policy.policy = IPSEC_POLICY_NONE;
- ip4_def_policy.refcnt++; /*never reclaim this*/
+ ip4_def_policy = key_newsp(0);
+ if (!ip4_def_policy)
+ panic("could not initialize IPv4 default security policy");
+ ip4_def_policy->state = IPSEC_SPSTATE_ALIVE;
+ ip4_def_policy->policy = IPSEC_POLICY_NONE;
+ ip4_def_policy->dir = IPSEC_DIR_ANY;
+ ip4_def_policy->readonly = 1;
+ ip4_def_policy->persist = 1;
#endif
#ifdef INET6
- ip6_def_policy.policy = IPSEC_POLICY_NONE;
- ip6_def_policy.refcnt++; /*never reclaim this*/
+ ip6_def_policy = key_newsp(0);
+ if (!ip6_def_policy)
+ panic("could not initialize IPv6 default security policy");
+ ip6_def_policy->state = IPSEC_SPSTATE_ALIVE;
+ ip6_def_policy->policy = IPSEC_POLICY_NONE;
+ ip6_def_policy->dir = IPSEC_DIR_ANY;
+ ip6_def_policy->readonly = 1;
+ ip6_def_policy->persist = 1;
#endif
-#ifndef IPSEC_DEBUG2
- timeout((void *)key_timehandler, (void *)0, hz);
-#endif /*IPSEC_DEBUG2*/
+ timeout(key_timehandler, (void *)0, hz);
/* initialize key statistics */
keystat.getspi_count = 1;
@@ -7270,8 +7392,6 @@ key_checktunnelsanity(sav, family, src, dst)
}
#if 0
-#define hostnamelen strlen(hostname)
-
/*
* Get FQDN for the host.
* If the administrator configured hostname (by hostname(1)) without
@@ -7283,6 +7403,7 @@ key_getfqdn()
int i;
int hasdot;
static char fqdn[MAXHOSTNAMELEN + 1];
+ int hostnamelen = strlen(hostname);
if (!hostnamelen)
return NULL;
@@ -7314,22 +7435,20 @@ key_getuserfqdn()
struct proc *p = curproc;
char *q;
- if (p == NULL)
- return NULL;
- bzero(userfqdn, sizeof(userfqdn));
- if (!(host = key_getfqdn())) {
+ PROC_LOCK(p);
+ if (!p || !p->p_pgrp || !p->p_pgrp->pg_session) {
PROC_UNLOCK(p);
return NULL;
}
- PROC_LOCK(p);
- if (!p->p_pgrp || !p->p_pgrp->pg_session) {
+ if (!(host = key_getfqdn())) {
PROC_UNLOCK(p);
return NULL;
}
/* NOTE: s_login may not be-NUL terminated. */
+ bzero(userfqdn, sizeof(userfqdn));
SESS_LOCK(p->p_session);
- bcopy(p->p_session->s_login, userfqdn, MAXLOGNAME);
+ bcopy(p->p_pgrp->pg_session->s_login, userfqdn, MAXLOGNAME);
SESS_UNLOCK(p->p_session);
PROC_UNLOCK(p);
userfqdn[MAXLOGNAME] = '\0'; /* safeguard */
@@ -7383,9 +7502,7 @@ key_sa_recordxfer(sav, m)
* <-----> SOFT
*/
{
- struct timeval tv;
- microtime(&tv);
- sav->lft_c->sadb_lifetime_usetime = tv.tv_sec;
+ sav->lft_c->sadb_lifetime_usetime = time_second;
/* XXX check for expires? */
}
@@ -7440,6 +7557,26 @@ key_sa_stir_iv(sav)
key_randomfill(sav->iv, sav->ivlen);
}
+static void
+key_sp_dead(sp)
+ struct secpolicy *sp;
+{
+
+ /* mark the SP dead */
+ sp->state = IPSEC_SPSTATE_DEAD;
+}
+
+static void
+key_sp_unlink(sp)
+ struct secpolicy *sp;
+{
+
+ /* remove from SP index */
+ if (__LIST_CHAINED(sp))
+ LIST_REMOVE(sp, chain);
+ key_freesp(sp);
+}
+
/* XXX too much? */
static struct mbuf *
key_alloc_mbuf(l)
diff --git a/sys/netkey/key.h b/sys/netkey/key.h
index 4cbe358..6bd1850 100644
--- a/sys/netkey/key.h
+++ b/sys/netkey/key.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: key.h,v 1.21 2001/07/27 03:51:30 itojun Exp $ */
+/* $KAME: key.h,v 1.32 2003/09/07 05:25:20 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -35,8 +35,13 @@
#ifdef _KERNEL
+#include <sys/queue.h>
+
extern struct key_cb key_cb;
+extern TAILQ_HEAD(_satailq, secasvar) satailq;
+extern TAILQ_HEAD(_sptailq, secpolicy) sptailq;
+
struct secpolicy;
struct secpolicyindex;
struct ipsecrequest;
@@ -46,22 +51,24 @@ struct socket;
struct sadb_msg;
struct sadb_x_policy;
-extern struct secpolicy *key_allocsp(struct secpolicyindex *, u_int);
+extern struct secpolicy *key_allocsp(u_int16_t, struct secpolicyindex *,
+ u_int);
extern struct secpolicy *key_gettunnel(struct sockaddr *,
struct sockaddr *, struct sockaddr *, struct sockaddr *);
extern int key_checkrequest
(struct ipsecrequest *isr, struct secasindex *);
extern struct secasvar *key_allocsa(u_int, caddr_t, caddr_t, u_int, u_int32_t);
extern void key_freesp(struct secpolicy *);
-extern void key_freeso(struct socket *);
extern void key_freesav(struct secasvar *);
-extern struct secpolicy *key_newsp(void);
+extern struct secpolicy *key_newsp(u_int32_t);
extern struct secpolicy *key_msg2sp(struct sadb_x_policy *, size_t, int *);
extern struct mbuf *key_sp2msg(struct secpolicy *);
-extern int key_ismyaddr(struct sockaddr *);
+extern int key_cmpspidx_exactly
+ (struct secpolicyindex *, struct secpolicyindex *);
+extern int key_cmpspidx_withmask
+ (struct secpolicyindex *, struct secpolicyindex *);
extern int key_spdacquire(struct secpolicy *);
-extern void key_timehandler(void);
-extern u_long key_random(void);
+extern void key_timehandler(void *);
extern void key_randomfill(void *, size_t);
extern void key_freereg(struct socket *);
extern int key_parse(struct mbuf *, struct socket *);
diff --git a/sys/netkey/key_debug.c b/sys/netkey/key_debug.c
index 35ed02f..a0de240 100644
--- a/sys/netkey/key_debug.c
+++ b/sys/netkey/key_debug.c
@@ -1,4 +1,4 @@
-/* $KAME: key_debug.c,v 1.26 2001/06/27 10:46:50 sakane Exp $ */
+/* $KAME: key_debug.c,v 1.38 2003/09/06 05:15:44 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -562,10 +562,11 @@ kdebug_secpolicy(sp)
if (sp == NULL)
panic("kdebug_secpolicy: NULL pointer was passed.");
- printf("secpolicy{ refcnt=%u state=%u policy=%u\n",
- sp->refcnt, sp->state, sp->policy);
+ printf("secpolicy{ refcnt=%u state=%u policy=%u dir=%u\n",
+ sp->refcnt, sp->state, sp->policy, sp->dir);
- kdebug_secpolicyindex(&sp->spidx);
+ if (sp->spidx)
+ kdebug_secpolicyindex(sp->spidx);
switch (sp->policy) {
case IPSEC_POLICY_DISCARD:
@@ -611,8 +612,8 @@ kdebug_secpolicyindex(spidx)
if (spidx == NULL)
panic("kdebug_secpolicyindex: NULL pointer was passed.");
- printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n",
- spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto);
+ printf("secpolicyindex{ prefs=%u prefd=%u ul_proto=%u\n",
+ spidx->prefs, spidx->prefd, spidx->ul_proto);
ipsec_hexdump((caddr_t)&spidx->src,
((struct sockaddr *)&spidx->src)->sa_len);
@@ -632,8 +633,7 @@ kdebug_secasindex(saidx)
if (saidx == NULL)
panic("kdebug_secpolicyindex: NULL pointer was passed.");
- printf("secasindex{ mode=%u proto=%u\n",
- saidx->mode, saidx->proto);
+ printf("secasindex{ mode=%u proto=%u\n", saidx->mode, saidx->proto);
ipsec_hexdump((caddr_t)&saidx->src,
((struct sockaddr *)&saidx->src)->sa_len);
@@ -697,8 +697,9 @@ kdebug_secreplay(rpl)
if (rpl == NULL)
panic("kdebug_secreplay: NULL pointer was passed.");
- printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u",
- rpl->count, rpl->wsize, rpl->seq, rpl->lastseq);
+ printf(" secreplay{ count=%llu wsize=%u seq=%llu lastseq=%llu",
+ (unsigned long long)rpl->count, rpl->wsize,
+ (unsigned long long)rpl->seq, (unsigned long long)rpl->lastseq);
if (rpl->bitmap == NULL) {
printf(" }\n");
@@ -736,9 +737,9 @@ kdebug_mbufhdr(m)
if (m->m_flags & M_EXT) {
printf(" m_ext{ ext_buf:%p ext_free:%p "
- "ext_size:%u ref_cnt:%p }\n",
+ "ext_size:%u }\n",
m->m_ext.ext_buf, m->m_ext.ext_free,
- m->m_ext.ext_size, m->m_ext.ref_cnt);
+ m->m_ext.ext_size);
}
return;
diff --git a/sys/netkey/keydb.c b/sys/netkey/keydb.c
index 309b512..697b6e5 100644
--- a/sys/netkey/keydb.c
+++ b/sys/netkey/keydb.c
@@ -1,4 +1,4 @@
-/* $KAME: keydb.c,v 1.64 2000/05/11 17:02:30 itojun Exp $ */
+/* $KAME: keydb.c,v 1.82 2003/09/07 07:47:33 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <net/pfkeyv2.h>
#include <netkey/keydb.h>
+#include <netkey/key.h>
#include <netinet6/ipsec.h>
#include <net/net_osdep.h>
@@ -69,17 +70,63 @@ keydb_newsecpolicy()
if (!p)
return p;
bzero(p, sizeof(*p));
+ TAILQ_INSERT_TAIL(&sptailq, p, tailq);
+
return p;
}
+u_int32_t
+keydb_newspid(void)
+{
+ u_int32_t newid = 0;
+ static u_int32_t lastalloc = IPSEC_MANUAL_POLICYID_MAX;
+ struct secpolicy *sp;
+
+ newid = lastalloc + 1;
+ /* XXX possible infinite loop */
+again:
+ TAILQ_FOREACH(sp, &sptailq, tailq) {
+ if (sp->id == newid)
+ break;
+ }
+ if (sp != NULL) {
+ if (newid + 1 < newid) /* wraparound */
+ newid = IPSEC_MANUAL_POLICYID_MAX + 1;
+ else
+ newid++;
+ goto again;
+ }
+ lastalloc = newid;
+
+ return newid;
+}
+
void
keydb_delsecpolicy(p)
struct secpolicy *p;
{
+ TAILQ_REMOVE(&sptailq, p, tailq);
+ if (p->spidx)
+ free(p->spidx, M_SECA);
free(p, M_SECA);
}
+int
+keydb_setsecpolicyindex(p, idx)
+ struct secpolicy *p;
+ struct secpolicyindex *idx;
+{
+
+ if (!p->spidx)
+ p->spidx = (struct secpolicyindex *)malloc(sizeof(*p->spidx),
+ M_SECA, M_NOWAIT);
+ if (!p->spidx)
+ return ENOMEM;
+ memcpy(p->spidx, idx, sizeof(*p->spidx));
+ return 0;
+}
+
/*
* secashead management
*/
@@ -112,12 +159,36 @@ keydb_delsecashead(p)
struct secasvar *
keydb_newsecasvar()
{
- struct secasvar *p;
+ struct secasvar *p, *q;
+ static u_int32_t said = 0;
p = (struct secasvar *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
if (!p)
return p;
+
+again:
+ said++;
+ if (said == 0)
+ said++;
+ TAILQ_FOREACH(q, &satailq, tailq) {
+ if (q->id == said)
+ goto again;
+ if (TAILQ_NEXT(q, tailq)) {
+ if (q->id < said && said < TAILQ_NEXT(q, tailq)->id)
+ break;
+ if (q->id + 1 < TAILQ_NEXT(q, tailq)->id) {
+ said = q->id + 1;
+ break;
+ }
+ }
+ }
+
bzero(p, sizeof(*p));
+ p->id = said;
+ if (q)
+ TAILQ_INSERT_AFTER(&satailq, q, p, tailq);
+ else
+ TAILQ_INSERT_TAIL(&satailq, p, tailq);
return p;
}
@@ -126,6 +197,8 @@ keydb_delsecasvar(p)
struct secasvar *p;
{
+ TAILQ_REMOVE(&satailq, p, tailq);
+
free(p, M_SECA);
}
@@ -144,7 +217,7 @@ keydb_newsecreplay(wsize)
bzero(p, sizeof(*p));
if (wsize != 0) {
- p->bitmap = (caddr_t)malloc(wsize, M_SECA, M_NOWAIT);
+ p->bitmap = malloc(wsize, M_SECA, M_NOWAIT);
if (!p->bitmap) {
free(p, M_SECA);
return NULL;
diff --git a/sys/netkey/keydb.h b/sys/netkey/keydb.h
index 0fce183..c9a4bb3 100644
--- a/sys/netkey/keydb.h
+++ b/sys/netkey/keydb.h
@@ -1,5 +1,5 @@
/* $FreeBSD$ */
-/* $KAME: keydb.h,v 1.14 2000/08/02 17:58:26 sakane Exp $ */
+/* $KAME: keydb.h,v 1.24 2003/09/07 15:12:10 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -72,7 +72,9 @@ struct secashead {
/* Security Association */
struct secasvar {
+ TAILQ_ENTRY(secasvar) tailq;
LIST_ENTRY(secasvar) chain;
+ LIST_ENTRY(secasvar) spihash;
int refcnt; /* reference count */
u_int8_t state; /* Status of this Association */
@@ -96,20 +98,22 @@ struct secasvar {
struct sadb_lifetime *lft_h; /* HARD lifetime */
struct sadb_lifetime *lft_s; /* SOFT lifetime */
- u_int32_t seq; /* sequence number */
+ u_int64_t seq; /* sequence number */
pid_t pid; /* message's pid */
struct secashead *sah; /* back pointer to the secashead */
+
+ u_int32_t id; /* SA id */
};
/* replay prevention */
struct secreplay {
- u_int32_t count;
+ u_int64_t count;
u_int wsize; /* window size, i.g. 4 bytes */
- u_int32_t seq; /* used by sender */
- u_int32_t lastseq; /* used by receiver */
- caddr_t bitmap; /* used by receiver */
- int overflow; /* overflow flag */
+ u_int64_t seq; /* used by sender */
+ u_int64_t lastseq; /* used by receiver */
+ u_int8_t *bitmap; /* used by receiver */
+ int overflow; /* what round does the counter take. */
};
/* socket table due to send PF_KEY messages. */
@@ -143,8 +147,13 @@ struct key_cb {
};
/* secpolicy */
+struct secpolicy;
+struct secpolicyindex;
extern struct secpolicy *keydb_newsecpolicy(void);
+extern u_int32_t keydb_newspid(void);
extern void keydb_delsecpolicy(struct secpolicy *);
+extern int keydb_setsecpolicyindex
+ (struct secpolicy *, struct secpolicyindex *);
/* secashead */
extern struct secashead *keydb_newsecashead(void);
extern void keydb_delsecashead(struct secashead *);
OpenPOWER on IntegriCloud