summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>2000-09-19 03:21:01 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>2000-09-19 03:21:01 +0000
commit6b556f468fe5379287b4856f719b265c452498d6 (patch)
tree4131e45ac41451e4b21f6f29bfef5fb5263f8ebe /sys
parentaf73df8e49a73ae51c26612cdf39434cf2ae6a75 (diff)
Lots and lots of changes.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/in.h8
-rw-r--r--sys/netinet/in_pcb.c7
-rw-r--r--sys/netinet/ip_ah.c37
-rw-r--r--sys/netinet/ip_ah.h6
-rw-r--r--sys/netinet/ip_esp.c25
-rw-r--r--sys/netinet/ip_esp.h6
-rw-r--r--sys/netinet/ip_ether.c6
-rw-r--r--sys/netinet/ip_input.c174
-rw-r--r--sys/netinet/ip_ipip.c50
-rw-r--r--sys/netinet/ip_ipip.h6
-rw-r--r--sys/netinet/ip_ipsp.c1687
-rw-r--r--sys/netinet/ip_ipsp.h175
-rw-r--r--sys/netinet/ip_output.c90
-rw-r--r--sys/netinet/ip_spd.c791
-rw-r--r--sys/netinet/ipsec_input.c152
-rw-r--r--sys/netinet/ipsec_output.c361
-rw-r--r--sys/netinet/raw_ip.c8
-rw-r--r--sys/netinet/tcp_input.c104
-rw-r--r--sys/netinet/tcp_usrreq.c10
-rw-r--r--sys/netinet/udp_usrreq.c90
20 files changed, 1992 insertions, 1801 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h
index ab6e9c2977e..6a70310720d 100644
--- a/sys/netinet/in.h
+++ b/sys/netinet/in.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: in.h,v 1.41 2000/09/18 22:06:36 provos Exp $ */
+/* $OpenBSD: in.h,v 1.42 2000/09/19 03:20:57 angelos Exp $ */
/* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */
/*
@@ -259,8 +259,6 @@ struct ip_opts {
#define IP_ESP_TRANS_LEVEL 21 /* int; transport encryption */
#define IP_ESP_NETWORK_LEVEL 22 /* int; full-packet encryption */
-#define IPSEC_OUTSA 39 /* set the outbound SA for a socket */
-
/*
* Security levels - IPsec, not IPSO
*/
@@ -434,7 +432,7 @@ struct ip_mreq {
#ifdef notdef /*obsolete*/
#define IPCTL_GIF_TTL 13 /* default TTL for gif encap packet */
#endif
-#define IPCTL_IPSEC_ACL 14 /* ingress IPsec access control */
+#define IPCTL_IPSEC_EXPIRE_ACQUIRE 14 /* How long to wait for key mgmt. */
#define IPCTL_IPSEC_EMBRYONIC_SA_TIMEOUT 15 /* new SA lifetime */
#define IPCTL_IPSEC_REQUIRE_PFS 16
#define IPCTL_IPSEC_SOFT_ALLOCATIONS 17
@@ -466,7 +464,7 @@ struct ip_mreq {
{ "maxqueue", CTLTYPE_INT }, \
{ "encdebug", CTLTYPE_INT }, \
{ 0, 0 }, \
- { "ipsec-acl", CTLTYPE_INT }, \
+ { "ipsec-expire-acquire", CTLTYPE_INT }, \
{ "ipsec-invalid-life", CTLTYPE_INT }, \
{ "ipsec-pfs", CTLTYPE_INT }, \
{ "ipsec-soft-allocs", CTLTYPE_INT }, \
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index f0fc288ca89..bbda223ea3a 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: in_pcb.c,v 1.43 2000/09/18 22:06:37 provos Exp $ */
+/* $OpenBSD: in_pcb.c,v 1.44 2000/09/19 03:20:57 angelos Exp $ */
/* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */
/*
@@ -78,8 +78,6 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#ifdef IPSEC
#include <netinet/ip_ipsp.h>
-
-extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#endif
#if 0 /*KAME IPSEC*/
@@ -499,7 +497,8 @@ in_pcbconnect(v, nam)
inp->inp_fport = sin->sin_port;
in_pcbrehash(inp);
#ifdef IPSEC
- return (check_ipsec_policy(inp, 0));
+ /* XXX Find IPsec TDB */
+ return (0);
#else
return (0);
#endif
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index ce448dfa7c9..fd0723b47a6 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_ah.c,v 1.43 2000/08/03 08:20:59 angelos Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.44 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
@@ -14,11 +14,12 @@
* Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
* and Niels Provos.
*
- * Additional features in 1999 by Angelos D. Keromytis.
+ * Additional features in 1999 by Angelos D. Keromytis and Niklas Hallqvist.
*
- * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
* Angelos D. Keromytis and Niels Provos.
- *
+ * Copyright (c) 1999 Niklas Hallqvist.
+ *
* Permission to use, copy, and modify this software without fee
* is hereby granted, provided that this entire notice is included in
* all copies of any software which is or includes a copy or
@@ -234,17 +235,17 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
HTONS(ip->ip_len);
HTONS(ip->ip_id);
- if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK))
- ip->ip_off = htons(ip->ip_off & IP_DF);
- else
- ip->ip_off = 0;
- }
+ if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK))
+ ip->ip_off = htons(ip->ip_off & IP_DF);
+ else
+ ip->ip_off = 0;
+ }
else
- {
- if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK))
- ip->ip_off = htons(ntohs(ip->ip_off) & IP_DF);
- else
- ip->ip_off = 0;
+ {
+ if ((alg == CRYPTO_MD5_KPDK) || (alg == CRYPTO_SHA1_KPDK))
+ ip->ip_off = htons(ntohs(ip->ip_off) & IP_DF);
+ else
+ ip->ip_off = 0;
}
ptr = mtod(m, unsigned char *) + sizeof(struct ip);
@@ -553,7 +554,7 @@ ah_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
(tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes))
{
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, TDBEXP_TIMEOUT);
+ tdb_delete(tdb, TDBEXP_TIMEOUT);
m_freem(m);
return ENXIO;
}
@@ -933,7 +934,7 @@ ah_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
(tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes))
{
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, TDBEXP_TIMEOUT);
+ tdb_delete(tdb, TDBEXP_TIMEOUT);
m_freem(m);
return EINVAL;
}
diff --git a/sys/netinet/ip_ah.h b/sys/netinet/ip_ah.h
index 45901eea86f..c3349e54c26 100644
--- a/sys/netinet/ip_ah.h
+++ b/sys/netinet/ip_ah.h
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_ah.h,v 1.25 2000/03/17 10:25:22 angelos Exp $ */
+/* $OpenBSD: ip_ah.h,v 1.26 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
index 818255f7b02..a64ff79fdd6 100644
--- a/sys/netinet/ip_esp.c
+++ b/sys/netinet/ip_esp.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_esp.c,v 1.48 2000/06/18 08:23:48 angelos Exp $ */
+/* $OpenBSD: ip_esp.c,v 1.49 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
@@ -355,7 +355,7 @@ esp_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff)
(tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes))
{
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, TDBEXP_TIMEOUT);
+ tdb_delete(tdb, TDBEXP_TIMEOUT);
m_freem(m);
return ENXIO;
}
@@ -807,7 +807,7 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
(tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes))
{
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, TDBEXP_TIMEOUT);
+ tdb_delete(tdb, TDBEXP_TIMEOUT);
m_freem(m);
return EINVAL;
}
@@ -878,8 +878,7 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
* Add padding -- better to do it ourselves than use the crypto engine,
* although if/when we support compression, we'd have to do that.
*/
- pad = (u_char *) m_pad(m, padding + alen,
- tdb->tdb_flags & TDBF_RANDOMPADDING);
+ pad = (u_char *) m_pad(m, padding + alen);
if (pad == NULL)
{
DPRINTF(("esp_output(): m_pad() failed for SA %s/%08x\n",
@@ -893,6 +892,10 @@ esp_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip,
for (ilen = 0; ilen < padding - 2; ilen++)
pad[ilen] = ilen + 1;
}
+ else
+ {
+ get_random_bytes((void *) pad, padding - 2); /* Random padding */
+ }
/* Fix padding length and Next Protocol in padding itself */
pad[padding - 2] = padding - 2;
@@ -1116,12 +1119,11 @@ checkreplaywindow32(u_int32_t seq, u_int32_t initial, u_int32_t *lastseq,
/*
* m_pad(m, n) pads <m> with <n> bytes at the end. The packet header
* length is updated, and a pointer to the first byte of the padding
- * (which is guaranteed to be all in one mbuf) is returned. The third
- * argument specifies whether we need randompadding or not.
+ * (which is guaranteed to be all in one mbuf) is returned.
*/
caddr_t
-m_pad(struct mbuf *m, int n, int randompadding)
+m_pad(struct mbuf *m, int n)
{
register struct mbuf *m0, *m1;
register int len, pad;
@@ -1176,8 +1178,5 @@ m_pad(struct mbuf *m, int n, int randompadding)
m0->m_len += pad;
m->m_pkthdr.len += pad;
- if (randompadding)
- get_random_bytes((void *) retval, n);
-
return retval;
}
diff --git a/sys/netinet/ip_esp.h b/sys/netinet/ip_esp.h
index f7cae5bbe6c..04f7c55d46d 100644
--- a/sys/netinet/ip_esp.h
+++ b/sys/netinet/ip_esp.h
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_esp.h,v 1.32 2000/03/17 10:25:22 angelos Exp $ */
+/* $OpenBSD: ip_esp.h,v 1.33 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
diff --git a/sys/netinet/ip_ether.c b/sys/netinet/ip_ether.c
index 97cc0ed77d6..645c1ee4471 100644
--- a/sys/netinet/ip_ether.c
+++ b/sys/netinet/ip_ether.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ether.c,v 1.9 2000/04/18 21:37:29 angelos Exp $ */
+/* $OpenBSD: ip_ether.c,v 1.10 2000/09/19 03:20:58 angelos Exp $ */
/*
* The author of this code is Angelos D. Keromytis (kermit@adk.gr)
@@ -155,10 +155,6 @@ va_dcl
/* Copy ethernet header */
m_copydata(m, 0, sizeof(eh), (void *) &eh);
- /* tdbi is only set in ESP or AH, if next protocol is UDP or TCP */
- if (m->m_flags & (M_CONF|M_AUTH))
- m->m_pkthdr.tdbi = NULL;
-
m->m_flags &= ~(M_BCAST|M_MCAST);
if (eh.ether_dhost[0] & 1)
{
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 792dc8886a1..41495f6693a 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_input.c,v 1.57 2000/09/18 22:06:37 provos Exp $ */
+/* $OpenBSD: ip_input.c,v 1.58 2000/09/19 03:20:58 angelos Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
@@ -66,6 +66,10 @@
#include <netinet/ip_icmp.h>
#include <netinet/ip_ipsp.h>
+#ifdef IPSEC
+#include <netinet/ip_ipsp.h>
+#endif /* IPSEC */
+
#ifndef IPFORWARDING
#ifdef GATEWAY
#define IPFORWARDING 1 /* forward IP packets not for us */
@@ -76,6 +80,9 @@
#ifndef IPSENDREDIRECTS
#define IPSENDREDIRECTS 1
#endif
+
+#define PI_MAGIC 0xdeadbeef /* XXX the horror! */
+
#ifndef IPMTUDISC
#define IPMTUDISC 0
#endif
@@ -84,7 +91,6 @@
#endif
int encdebug = 0;
-int ipsec_acl = 1;
int ipsec_keep_invalid = IPSEC_DEFAULT_EMBRYONIC_SA_TIMEOUT;
int ipsec_require_pfs = IPSEC_DEFAULT_PFS;
int ipsec_soft_allocations = IPSEC_DEFAULT_SOFT_ALLOCATIONS;
@@ -95,6 +101,7 @@ int ipsec_soft_timeout = IPSEC_DEFAULT_SOFT_TIMEOUT;
int ipsec_exp_timeout = IPSEC_DEFAULT_EXP_TIMEOUT;
int ipsec_soft_first_use = IPSEC_DEFAULT_SOFT_FIRST_USE;
int ipsec_exp_first_use = IPSEC_DEFAULT_EXP_FIRST_USE;
+int ipsec_expire_acquire = IPSEC_DEFAULT_EXPIRE_ACQUIRE;
char ipsec_def_enc[20];
char ipsec_def_auth[20];
@@ -293,14 +300,30 @@ ipv4_input(struct mbuf *m, ...)
int hlen, mff;
va_list ap;
int extra;
+#ifdef IPSEC
+ int error, s;
+ struct tdb *tdb;
+ struct tdb_ident *tdbi;
+#endif /* IPSEC */
va_start(ap, m);
extra = va_arg(ap, int);
va_end(ap);
+#ifdef IPSEC
+ tdbi = (struct tdb_ident *) m->m_pkthdr.tdbi;
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
+#endif /* IPSEC */
+
if (extra) {
struct mbuf *newpacket;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
+
if (!(newpacket = m_split(m, extra, M_NOWAIT))) {
m_freem(m);
return;
@@ -322,6 +345,10 @@ ipv4_input(struct mbuf *m, ...)
if (m->m_len < sizeof (struct ip) &&
(m = m_pullup(m, sizeof (struct ip))) == 0) {
ipstat.ips_toosmall++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
ip = mtod(m, struct ip *);
@@ -337,6 +364,10 @@ ipv4_input(struct mbuf *m, ...)
if (hlen > m->m_len) {
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_badhlen++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
ip = mtod(m, struct ip *);
@@ -382,8 +413,13 @@ ipv4_input(struct mbuf *m, ...)
*/
{
struct mbuf *m0 = m;
- if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m0))
+ if (fr_checkp && (*fr_checkp)(ip, hlen, m->m_pkthdr.rcvif, 0, &m0)) {
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
+ }
ip = mtod(m = m0, struct ip *);
}
#endif
@@ -395,8 +431,13 @@ ipv4_input(struct mbuf *m, ...)
* to be sent and the original packet to be freed).
*/
ip_nhops = 0; /* for source routed packets */
- if (hlen > sizeof (struct ip) && ip_dooptions(m))
- return;
+ if (hlen > sizeof (struct ip) && ip_dooptions(m)) {
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
+ return;
+ }
/*
* Check our list of addresses, to see if the packet is for us.
@@ -413,6 +454,10 @@ ipv4_input(struct mbuf *m, ...)
if (m->m_flags & M_EXT) {
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_toosmall++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
ip = mtod(m, struct ip *);
@@ -434,6 +479,10 @@ ipv4_input(struct mbuf *m, ...)
ip->ip_id = htons(ip->ip_id);
if (ip_mforward(m, m->m_pkthdr.rcvif) != 0) {
ipstat.ips_cantforward++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return;
}
@@ -457,6 +506,10 @@ ipv4_input(struct mbuf *m, ...)
if (inm == NULL) {
ipstat.ips_cantforward++;
m_freem(m);
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
goto ours;
@@ -470,9 +523,41 @@ ipv4_input(struct mbuf *m, ...)
*/
if (ipforwarding == 0) {
ipstat.ips_cantforward++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
- } else
+ } else {
+#ifdef IPSEC
+ /* IPsec policy check for forwarded packets */
+ s = splnet();
+ if (tdbi == NULL)
+ tdb = NULL;
+ else
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+
+ ipsp_spd_lookup(m, AF_INET, hlen, &error,
+ IPSP_DIRECTION_IN, tdb, NULL);
+ splx(s);
+
+ /* Error or otherwise drop-packet indication */
+ if (error) {
+ ipstat.ips_cantforward++;
+ m_freem(m);
+ return;
+ }
+
+ if (tdbi) {
+ free(tdbi, M_TEMP);
+ m->m_pkthdr.tdbi = NULL;
+ }
+
+ /* Fall through, forward packet */
+#endif /* IPSEC */
+
ip_forward(m, 0);
+ }
return;
ours:
@@ -487,6 +572,10 @@ ours:
if (m->m_flags & M_EXT) { /* XXX */
if ((m = m_pullup(m, hlen)) == 0) {
ipstat.ips_toosmall++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
ip = mtod(m, struct ip *);
@@ -553,6 +642,10 @@ found:
ip = ip_reass(ipqe, fp);
if (ip == 0) {
ipq_unlock();
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
ipstat.ips_reassembled++;
@@ -565,6 +658,66 @@ found:
} else
ip->ip_len -= hlen;
+#ifdef IPSEC
+ /*
+ * If it's a protected packet for us, skip the policy check.
+ * That's because we really only care about the properties of
+ * the protected packet, and not the intermediate versions.
+ * While this is not the most paranoid setting, it allows
+ * some flexibility in handling of nested tunnels etc.
+ */
+ if ((ip->ip_p == IPPROTO_ESP) || (ip->ip_p == IPPROTO_AH))
+ goto skipipsec;
+
+ /*
+ * If the protected packet was tunneled, then we need to
+ * verify the protected packet's information, not the
+ * external headers. Thus, skip the policy lookup for the
+ * external packet, and keep the IPsec information linked on
+ * the packet header (the encapsulation routines know how
+ * to deal with that).
+ */
+ if ((ip->ip_p == IPPROTO_IPIP) || (ip->ip_p == IPPROTO_IPV6))
+ goto skipipsec2;
+
+ /*
+ * If the protected packet is TCP or UDP, we'll do the
+ * policy check in the respective input routine, so we can
+ * check for bypass sockets.
+ */
+ if ((ip->ip_p == IPPROTO_TCP) || (ip->ip_p == IPPROTO_UDP))
+ goto skipipsec2;
+
+ /* IPsec policy check for local-delivery packets */
+ s = splnet();
+ if (tdbi == NULL)
+ tdb = NULL;
+ else
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+
+ ipsp_spd_lookup(m, AF_INET, hlen, &error, IPSP_DIRECTION_IN,
+ tdb, NULL);
+ splx(s);
+
+ /* Error or otherwise drop-packet indication */
+ if (error) {
+ ipstat.ips_cantforward++;
+ if (tdbi)
+ free(tdbi, M_TEMP);
+ m_freem(m);
+ return;
+ }
+
+ skipipsec:
+ if (tdbi) {
+ free(tdbi, M_TEMP);
+ m->m_pkthdr.tdbi = NULL;
+ }
+
+ skipipsec2:
+ /* Otherwise, just fall through and deliver the packet */
+#endif /* IPSEC */
+
/*
* Switch out to protocol's input routine.
*/
@@ -572,6 +725,10 @@ found:
(*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen, NULL, 0);
return;
bad:
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
}
@@ -1546,8 +1703,6 @@ ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
&ip_maxqueue));
case IPCTL_ENCDEBUG:
return (sysctl_int(oldp, oldlenp, newp, newlen, &encdebug));
- case IPCTL_IPSEC_ACL:
- return (sysctl_int(oldp, oldlenp, newp, newlen, &ipsec_acl));
case IPCTL_IPSEC_EMBRYONIC_SA_TIMEOUT:
return (sysctl_int(oldp, oldlenp, newp, newlen,
&ipsec_keep_invalid));
@@ -1585,6 +1740,9 @@ ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
return (sysctl_tstring(oldp, oldlenp, newp, newlen,
ipsec_def_auth,
sizeof(ipsec_def_auth)));
+ case IPCTL_IPSEC_EXPIRE_ACQUIRE:
+ return (sysctl_int(oldp, oldlenp, newp, newlen,
+ &ipsec_expire_acquire));
default:
return (EOPNOTSUPP);
}
diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c
index 4ca9f239a20..f680237f672 100644
--- a/sys/netinet/ip_ipip.c
+++ b/sys/netinet/ip_ipip.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_ipip.c,v 1.8 2000/08/04 00:26:58 angelos Exp $ */
+/* $OpenBSD: ip_ipip.c,v 1.9 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
@@ -87,6 +87,8 @@
#define offsetof(s, e) ((int)&((s *)0)->e)
#endif
+#define PI_MAGIC 0xdeadbeef /* XXX */
+
/*
* We can control the acceptance of IP4 packets by altering the sysctl
* net.inet.ipip.allow value. Zero means drop them, all else is acceptance.
@@ -102,11 +104,18 @@ struct ipipstat ipipstat;
int
ip4_input6(struct mbuf **m, int *offp, int proto)
{
+ void *tdbi = (*m)->m_pkthdr.tdbi;
+
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
+
/* If we do not accept IPv4 explicitly, drop. */
if (!ipip_allow && ((*m)->m_flags & (M_AUTH|M_CONF)) == 0)
{
DPRINTF(("ip4_input6(): dropped due to policy\n"));
ipipstat.ipips_pdrops++;
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(*m);
return IPPROTO_DONE;
}
@@ -125,12 +134,18 @@ ip4_input(struct mbuf *m, ...)
{
va_list ap;
int iphlen;
+ void *tdbi = m->m_pkthdr.tdbi;
+
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
/* If we do not accept IPv4 explicitly, drop. */
if (!ipip_allow && (m->m_flags & (M_AUTH|M_CONF)) == 0)
{
DPRINTF(("ip4_input(): dropped due to policy\n"));
ipipstat.ipips_pdrops++;
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(m);
return;
}
@@ -168,9 +183,13 @@ ipip_input(struct mbuf *m, int iphlen)
u_int8_t otos;
u_int8_t v;
int hlen, s;
+ void *tdbi = m->m_pkthdr.tdbi;
ipipstat.ipips_ipackets++;
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
+
m_copydata(m, 0, 1, &v);
switch (v >> 4)
@@ -187,6 +206,8 @@ ipip_input(struct mbuf *m, int iphlen)
break;
#endif
default:
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(m);
return /* EAFNOSUPPORT */;
}
@@ -198,7 +219,8 @@ ipip_input(struct mbuf *m, int iphlen)
{
DPRINTF(("ipip_input(): m_pullup() failed\n"));
ipipstat.ipips_hdrops++;
- m_freem(m);
+ if (tdbi)
+ free(tdbi, M_TEMP);
return;
}
}
@@ -210,6 +232,12 @@ ipip_input(struct mbuf *m, int iphlen)
{
if (IN_MULTICAST(((struct ip *)((char *) ipo + iphlen))->ip_dst.s_addr))
{
+ if (tdbi)
+ {
+ free(tdbi, M_TEMP);
+ m->m_pkthdr.tdbi = NULL;
+ }
+
ipip_mroute_input (m, iphlen);
return;
}
@@ -248,6 +276,8 @@ ipip_input(struct mbuf *m, int iphlen)
#endif
default:
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(m);
return /* EAFNOSUPPORT */;
}
@@ -258,6 +288,8 @@ ipip_input(struct mbuf *m, int iphlen)
if ((m = m_pullup(m, hlen)) == 0)
{
DPRINTF(("ipip_input(): m_pullup() failed\n"));
+ if (tdbi)
+ free(tdbi, M_TEMP);
ipipstat.ipips_hdrops++;
return;
}
@@ -314,6 +346,8 @@ ipip_input(struct mbuf *m, int iphlen)
{
DPRINTF(("ipip_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst)));
ipipstat.ipips_spoof++;
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(m);
return;
}
@@ -331,6 +365,8 @@ ipip_input(struct mbuf *m, int iphlen)
if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src))
{
DPRINTF(("ipip_input(): possible local address spoofing detected on packet\n"));
+ if (tdbi)
+ free(tdbi, M_TEMP);
m_freem(m);
return;
}
@@ -344,10 +380,6 @@ ipip_input(struct mbuf *m, int iphlen)
/* Statistics */
ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen;
- /* tdbi is only set in ESP or AH, if the next protocol is UDP or TCP */
- if (m->m_flags & (M_CONF|M_AUTH))
- m->m_pkthdr.tdbi = NULL;
-
/*
* Interface pointer stays the same; if no IPsec processing has
* been done (or will be done), this will point to a normal
@@ -377,6 +409,8 @@ ipip_input(struct mbuf *m, int iphlen)
{
IF_DROP(ifq);
m_freem(m);
+ if (tdbi)
+ free(tdbi, M_TEMP);
ipipstat.ipips_qfull++;
splx(s);
diff --git a/sys/netinet/ip_ipip.h b/sys/netinet/ip_ipip.h
index c413e139ca2..d8a45204046 100644
--- a/sys/netinet/ip_ipip.h
+++ b/sys/netinet/ip_ipip.h
@@ -1,12 +1,12 @@
-/* $OpenBSD: ip_ipip.h,v 1.1 2000/01/21 03:15:05 angelos Exp $ */
+/* $OpenBSD: ip_ipip.h,v 1.2 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
* Niels Provos (provos@physnet.uni-hamburg.de).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index b5af2ba3071..2ef04505cee 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.99 2000/08/03 08:31:39 angelos Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.100 2000/09/19 03:20:58 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -6,8 +6,8 @@
* Niels Provos (provos@physnet.uni-hamburg.de) and
* Niklas Hallqvist (niklas@appli.se).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
@@ -41,12 +41,10 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
-#include <sys/protosw.h>
#include <sys/socket.h>
-#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/kernel.h>
-#include <sys/proc.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/route.h>
@@ -54,9 +52,9 @@
#ifdef INET
#include <netinet/in.h>
#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
-#include <netinet/ip_var.h>
#endif /* INET */
#ifdef INET6
@@ -69,10 +67,7 @@
#include <net/pfkeyv2.h>
#include <netinet/ip_ipsp.h>
-#include <netinet/ip_ah.h>
-#include <netinet/ip_esp.h>
-#include <crypto/crypto.h>
#include <crypto/xform.h>
#include <dev/rndvar.h>
@@ -98,7 +93,6 @@ void tdb_hashstats(void);
int ipsp_kern __P((int, char **, int));
u_int8_t get_sa_require __P((struct inpcb *));
-int check_ipsec_policy __P((struct inpcb *, void *));
void tdb_rehash __P((void));
extern int ipsec_auth_default_level;
@@ -107,11 +101,16 @@ extern int ipsec_esp_network_default_level;
extern int encdebug;
int ipsec_in_use = 0;
+u_int64_t ipsec_last_added = 0;
u_int32_t kernfs_epoch = 0;
struct expclusterlist_head expclusterlist =
TAILQ_HEAD_INITIALIZER(expclusterlist);
struct explist_head explist = TAILQ_HEAD_INITIALIZER(explist);
+struct ipsec_policy_head ipsec_policy_head =
+ TAILQ_HEAD_INITIALIZER(ipsec_policy_head);
+struct ipsec_acquire_head ipsec_acquire_head =
+ TAILQ_HEAD_INITIALIZER(ipsec_acquire_head);
/*
* This is the proper place to define the various encapsulation transforms.
@@ -141,302 +140,54 @@ struct xformsw *xformswNXFORMSW = &xformsw[sizeof(xformsw)/sizeof(xformsw[0])];
unsigned char ipseczeroes[IPSEC_ZEROES_SIZE]; /* zeroes! */
#define TDB_HASHSIZE_INIT 32
-static struct tdb **tdbh = NULL, *tdb_bypass = NULL;
+static struct tdb **tdbh = NULL;
+static struct tdb **tdbaddr = NULL;
+static struct tdb **tdbsrc = NULL;
static u_int tdb_hashmask = TDB_HASHSIZE_INIT - 1;
static int tdb_count;
/*
- * Check which transformations are required.
- */
-u_int8_t
-get_sa_require(struct inpcb *inp)
-{
- u_int8_t sareq = 0;
-
- if (inp != NULL)
- {
- sareq |= inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_AUTH : 0;
- sareq |= inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_CONF : 0;
- sareq |= inp->inp_seclevel[SL_ESP_NETWORK] >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_TUNNEL : 0;
- }
- else
- {
- sareq |= ipsec_auth_default_level >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_AUTH : 0;
- sareq |= ipsec_esp_trans_default_level >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_CONF : 0;
- sareq |= ipsec_esp_network_default_level >= IPSEC_LEVEL_USE ?
- NOTIFY_SATYPE_TUNNEL : 0;
- }
-
- return (sareq);
-}
-
-/*
- * Check the socket policy and request a new SA with a key management
- * daemon. Sometimes inp does not contain the destination address;
- * in that case use dst.
+ * Our hashing function needs to stir things with a non-zero random multiplier
+ * so we cannot be DoS-attacked via choosing of the data to hash.
*/
-int
-check_ipsec_policy(struct inpcb *inp, void *daddr)
+INLINE int
+tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
{
- struct route_enc re0, *re = &re0;
- struct sockaddr_encap *dst, *gw;
- u_int8_t sa_require, sa_have;
- struct tdb tdb2, *tdb = NULL;
- union sockaddr_union sunion;
- struct socket *so;
- int error, i, s;
-
- if (inp == NULL || ((so = inp->inp_socket) == 0))
- return (EINVAL);
-
- /* If IPsec is not required just use what we got */
- if (!(sa_require = inp->inp_secrequire))
- return 0;
-
- s = spltdb();
- if (!inp->inp_tdb)
- {
- bzero((caddr_t) re, sizeof(*re));
- dst = (struct sockaddr_encap *) &re->re_dst;
- dst->sen_family = PF_KEY;
-
-#ifdef INET6
- if (inp->inp_flags & INP_IPV6)
- {
- dst->sen_len = SENT_IP6_LEN;
- dst->sen_type = SENT_IP6;
- dst->sen_ip6_src = inp->inp_laddr6;
- if (inp->inp_faddr6.s6_addr)
- dst->sen_ip6_dst = inp->inp_faddr6;
- else
- dst->sen_ip6_dst = (*((struct in6_addr *) daddr));
-
- dst->sen_ip6_proto = so->so_proto->pr_protocol;
-
- switch (dst->sen_ip6_proto)
- {
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- dst->sen_ip6_sport = htons(inp->inp_lport);
- dst->sen_ip6_dport = htons(inp->inp_fport);
- break;
-
- default:
- dst->sen_ip6_sport = 0;
- dst->sen_ip6_dport = 0;
- }
- }
-#endif /* INET6 */
-
-#ifdef INET
- if (!(inp->inp_flags & INP_IPV6))
- {
- dst->sen_len = SENT_IP4_LEN;
- dst->sen_type = SENT_IP4;
- dst->sen_ip_src = inp->inp_laddr;
-
- if (inp->inp_faddr.s_addr)
- dst->sen_ip_dst = inp->inp_faddr;
- else
- dst->sen_ip_dst = (*((struct in_addr *) daddr));
-
- dst->sen_proto = so->so_proto->pr_protocol;
-
- switch (dst->sen_proto)
- {
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- dst->sen_sport = htons(inp->inp_lport);
- dst->sen_dport = htons(inp->inp_fport);
- break;
-
- default:
- dst->sen_sport = 0;
- dst->sen_dport = 0;
- }
- }
-#endif /* INET */
-
- /* Try to find a flow */
- rtalloc((struct route *) re);
-
- if (re->re_rt != NULL)
- {
- gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
-
-#ifdef INET
- if (gw->sen_type == SENT_IPSP)
- {
- bzero(&sunion, sizeof(sunion));
- sunion.sin.sin_family = AF_INET;
- sunion.sin.sin_len = sizeof(struct sockaddr_in);
- sunion.sin.sin_addr = gw->sen_ipsp_dst;
-
- tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
- gw->sen_ipsp_sproto);
- }
-#endif /* INET */
-
-#ifdef INET6
- if (gw->sen_type == SENT_IPSP6)
- {
- bzero(&sunion, sizeof(sunion));
- sunion.sin6.sin6_family = AF_INET6;
- sunion.sin6.sin6_len = sizeof(struct sockaddr_in6);
- sunion.sin6.sin6_addr = gw->sen_ipsp6_dst;
-
- tdb = (struct tdb *) gettdb(gw->sen_ipsp6_spi, &sunion,
- gw->sen_ipsp6_sproto);
- }
-#endif /* INET6 */
-
- RTFREE(re->re_rt);
- }
- }
- else
- tdb = inp->inp_tdb;
-
- if (tdb)
- SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);
- else
- sa_have = 0;
-
- splx(s);
-
- /* Check if our requirements are met */
- if (!(sa_require & ~sa_have))
- return 0;
-
- error = i = 0;
+ static u_int32_t mult1 = 0, mult2 = 0;
+ u_int8_t *ptr = (u_int8_t *) dst;
+ int i, shift;
+ u_int64_t hash;
+ int val32 = 0;
- inp->inp_secresult = SR_WAIT;
+ while (mult1 == 0)
+ mult1 = arc4random();
+ while (mult2 == 0)
+ mult2 = arc4random();
- /* If necessary try to notify keymanagement three times */
- while (i < 3)
+ hash = (spi ^ proto) * mult1;
+ for (i = 0; i < SA_LEN(&dst->sa); i++)
{
- switch (dst->sen_type)
- {
-#ifdef INET
- case SENT_IP4:
- DPRINTF(("ipsec: send SA request (%d), remote IPv4 address: %s, SA type: %d\n", i + 1, inet_ntoa4(dst->sen_ip_dst), sa_require));
- break;
-#endif /* INET */
-
-#ifdef INET6
- case SENT_IP6:
- DPRINTF(("ipsec: send SA request (%d), remote IPv6 address: %s, SA type: %d\n", i + 1, ip6_sprintf(&dst->sen_ip6_dst), sa_require));
- break;
-#endif /* INET6 */
-
- default:
- DPRINTF(("ipsec: unsupported protocol family %d, cannot notify kkey management\n", dst->sen_type));
- return EPFNOSUPPORT;
- }
-
- /* Initialize TDB for PF_KEY notification */
- bzero(&tdb2, sizeof(tdb2));
- tdb2.tdb_satype = get_sa_require(inp);
-
-#ifdef INET
- if (!(inp->inp_flags & INP_IPV6))
- {
- tdb2.tdb_src.sin.sin_family = AF_INET;
- tdb2.tdb_src.sin.sin_len = sizeof(struct sockaddr_in);
- tdb2.tdb_src.sin.sin_addr = inp->inp_laddr;
-
- tdb2.tdb_dst.sin.sin_family = AF_INET;
- tdb2.tdb_dst.sin.sin_len = sizeof(struct sockaddr_in);
- tdb2.tdb_dst.sin.sin_addr = inp->inp_faddr;
- }
-#endif /* INET */
-
-#ifdef INET6
- if (inp->inp_flags & INP_IPV6)
+ val32 = (val32 << 8) | ptr[i];
+ if (i % 4 == 3)
{
- tdb2.tdb_src.sin6.sin6_family = AF_INET6;
- tdb2.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6);
- tdb2.tdb_src.sin6.sin6_addr = inp->inp_laddr6;
-
- tdb2.tdb_dst.sin6.sin6_family = AF_INET6;
- tdb2.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
- tdb2.tdb_dst.sin6.sin6_addr = inp->inp_faddr6;
+ hash ^= val32 * mult2;
+ val32 = 0;
}
-#endif /* INET6 */
-
- error = ipsp_acquire_sa(&tdb2);
- if (error)
- return error;
-
- /*
- * Wait for the keymanagement daemon to establich a new SA,
- * even on error check again, perhaps some other process
- * already established the necessary SA.
- */
- error = tsleep((caddr_t)inp, PSOCK|PCATCH, "ipsecnotify", 30*hz);
- DPRINTF(("check_ipsec: sleep %d\n", error));
-
- if (error && error != EWOULDBLOCK)
- break;
-
- /*
- * A Key Management daemon returned an apropriate SA back
- * to the kernel, the kernel noted that state in the waiting
- * socket.
- */
- if (inp->inp_secresult == SR_SUCCESS)
- return (0);
-
- /*
- * Key Management returned a permanent failure, we do not
- * need to retry again.
- *
- * XXX when more than one key management daemon is available
- * XXX we can not do that.
- */
- if (inp->inp_secresult == SR_FAILED)
- break;
-
- i++;
}
- return (error ? error : EWOULDBLOCK);
-}
-
-/*
- * Add an inpcb to the list of inpcb which reference this tdb directly.
- */
-void
-tdb_add_inp(struct tdb *tdb, struct inpcb *inp)
-{
- int s = spltdb();
-
- if (inp->inp_tdb)
- {
- if (inp->inp_tdb == tdb)
- {
- splx(s);
- return;
- }
-
- TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next);
- }
+ if (i % 4 != 0)
+ hash ^= val32 * mult2;
- inp->inp_tdb = tdb;
- TAILQ_INSERT_TAIL(&tdb->tdb_inp, inp, inp_tdb_next);
- splx(s);
+ shift = ffs(tdb_hashmask + 1);
+ while ((hash & ~tdb_hashmask) != 0)
+ hash = (hash >> shift) ^ (hash & tdb_hashmask);
- DPRINTF(("tdb_add_inp: tdb: %p, inp: %p\n", tdb, inp));
+ return hash;
}
/*
- * Reserve an SPI; the SA is not valid yet though. We use SPI_LOCAL_USE as
- * an error return value. It'll not be a problem that we also use that
- * for demand-keying as that is manually specified.
+ * Reserve an SPI; the SA is not valid yet though. We use 0 as
+ * an error return value.
*/
u_int32_t
reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src,
@@ -460,7 +211,7 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src,
if (sspi == tspi) /* Asking for a specific SPI */
nums = 1;
else
- nums = 100; /* XXX figure out some good value */
+ nums = 100; /* Arbitrarily chosen */
while (nums--)
{
@@ -473,8 +224,7 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src,
}
/* Don't allocate reserved SPIs. */
- if (spi == SPI_LOCAL_USE ||
- (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX))
+ if (spi >= SPI_RESERVED_MIN && spi <= SPI_RESERVED_MAX)
continue;
else
spi = htonl(spi);
@@ -516,44 +266,6 @@ reserve_spi(u_int32_t sspi, u_int32_t tspi, union sockaddr_union *src,
}
/*
- * Our hashing function needs to stir things with a non-zero random multiplier
- * so we cannot be DoS-attacked via choosing of the data to hash.
- */
-INLINE int
-tdb_hash(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
-{
- static u_int32_t mult1 = 0, mult2 = 0;
- u_int8_t *ptr = (u_int8_t *) dst;
- int i, shift;
- u_int64_t hash;
- int val32 = 0;
-
- while (mult1 == 0)
- mult1 = arc4random();
- while (mult2 == 0)
- mult2 = arc4random();
-
- hash = (spi ^ proto) * mult1;
- for (i = 0; i < SA_LEN(&dst->sa); i++)
- {
- val32 = (val32 << 8) | ptr[i];
- if (i % 4 == 3)
- {
- hash ^= val32 * mult2;
- val32 = 0;
- }
- }
- if (i % 4 != 0)
- hash ^= val32 * mult2;
-
- shift = ffs(tdb_hashmask + 1);
- while ((hash & ~tdb_hashmask) != 0)
- hash = (hash >> shift) ^ (hash & tdb_hashmask);
-
- return hash;
-}
-
-/*
* An IPSP SAID is really the concatenation of the SPI found in the
* packet, the destination address of the packet and the IPsec protocol.
* When we receive an IPSP packet, we need to look up its tunnel descriptor
@@ -567,40 +279,6 @@ gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
{
u_int32_t hashval;
struct tdb *tdbp;
- int s;
-
- if (spi == 0 && proto == 0)
- {
- /*
- * tdb_bypass; a placeholder for bypass flows, allocate on
- * first pass.
- */
- if (tdb_bypass == NULL)
- {
- s = spltdb();
- MALLOC(tdb_bypass, struct tdb *, sizeof(struct tdb), M_TDB,
- M_WAITOK);
- tdb_count++;
- splx(s);
-
- bzero(tdb_bypass, sizeof(struct tdb));
- tdb_bypass->tdb_satype = SADB_X_SATYPE_BYPASS;
- tdb_bypass->tdb_established = time.tv_sec;
- tdb_bypass->tdb_epoch = kernfs_epoch - 1;
- tdb_bypass->tdb_flags = 0;
-
-#ifdef INET
- tdb_bypass->tdb_dst.sa.sa_family = AF_INET;
-#elif INET6
- tdb_bypass->tdb_dst.sa.sa_family = AF_INET6;
-#endif
-
- TAILQ_INIT(&tdb_bypass->tdb_bind_in);
- TAILQ_INIT(&tdb_bypass->tdb_inp);
- }
-
- return tdb_bypass;
- }
if (tdbh == NULL)
return (struct tdb *) NULL;
@@ -616,6 +294,96 @@ gettdb(u_int32_t spi, union sockaddr_union *dst, u_int8_t proto)
return tdbp;
}
+/*
+ * Get an SA given the remote address, the security protocol type, and
+ * the desired IDs.
+ */
+struct tdb *
+gettdbbyaddr(union sockaddr_union *dst, u_int8_t proto, struct mbuf *m, int af)
+{
+ u_int32_t hashval;
+ struct tdb *tdbp;
+
+ if (tdbaddr == NULL)
+ return (struct tdb *) NULL;
+
+ hashval = tdb_hash(0, dst, proto);
+
+ for (tdbp = tdbaddr[hashval]; tdbp != NULL; tdbp = tdbp->tdb_anext)
+ if ((tdbp->tdb_sproto == proto) &&
+ ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
+ (!bcmp(&tdbp->tdb_dst, dst, SA_LEN(&dst->sa))))
+ {
+ /*
+ * If the IDs are not set, this was probably a manually-keyed
+ * SA, so it can be used for any type of traffic.
+ */
+ if ((tdbp->tdb_srcid == NULL) && (tdbp->tdb_dstid == NULL))
+ break;
+
+ /* Not sure how to deal with half-set IDs...just skip the SA */
+ if ((tdbp->tdb_srcid == NULL) || (tdbp->tdb_dstid == NULL))
+ continue;
+
+ /* We only grok addresses */
+ if (((tdbp->tdb_srcid_type != SADB_IDENTTYPE_PREFIX) &&
+ (tdbp->tdb_dstid_type != SADB_IDENTTYPE_CONNECTION)) ||
+ ((tdbp->tdb_dstid_type != SADB_IDENTTYPE_PREFIX) &&
+ (tdbp->tdb_dstid_type != SADB_IDENTTYPE_CONNECTION)))
+ continue;
+
+ /* XXX Check the IDs ? */
+ break;
+ }
+
+ return tdbp;
+}
+
+/*
+ * Get an SA given the source address, the security protocol type, and
+ * the desired IDs.
+ */
+struct tdb *
+gettdbbysrc(union sockaddr_union *src, u_int8_t proto, struct mbuf *m, int af)
+{
+ u_int32_t hashval;
+ struct tdb *tdbp;
+
+ if (tdbsrc == NULL)
+ return (struct tdb *) NULL;
+
+ hashval = tdb_hash(0, src, proto);
+
+ for (tdbp = tdbsrc[hashval]; tdbp != NULL; tdbp = tdbp->tdb_snext)
+ if ((tdbp->tdb_sproto == proto) &&
+ ((tdbp->tdb_flags & TDBF_INVALID) == 0) &&
+ (!bcmp(&tdbp->tdb_src, src, SA_LEN(&src->sa))))
+ {
+ /*
+ * If the IDs are not set, this was probably a manually-keyed
+ * SA, so it can be used for any type of traffic.
+ */
+ if ((tdbp->tdb_srcid == NULL) && (tdbp->tdb_dstid == NULL))
+ break;
+
+ /* Not sure how to deal with half-set IDs...just skip the SA */
+ if ((tdbp->tdb_srcid == NULL) || (tdbp->tdb_dstid == NULL))
+ continue;
+
+ /* We only grok addresses */
+ if (((tdbp->tdb_srcid_type != SADB_IDENTTYPE_PREFIX) &&
+ (tdbp->tdb_dstid_type != SADB_IDENTTYPE_CONNECTION)) ||
+ ((tdbp->tdb_dstid_type != SADB_IDENTTYPE_PREFIX) &&
+ (tdbp->tdb_dstid_type != SADB_IDENTTYPE_CONNECTION)))
+ continue;
+
+ /* XXX Check the IDs ? */
+ break;
+ }
+
+ return tdbp;
+}
+
#if DDB
void
tdb_hashstats(void)
@@ -658,27 +426,15 @@ tdb_walk(int (*walker)(struct tdb *, void *), void *arg)
return ENOENT;
for (i = 0; i <= tdb_hashmask; i++)
- for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next)
- {
- next = tdbp->tdb_hnext;
- rval = walker(tdbp, (void *)arg);
- }
+ for (tdbp = tdbh[i]; rval == 0 && tdbp != NULL; tdbp = next)
+ {
+ next = tdbp->tdb_hnext;
+ rval = walker(tdbp, (void *)arg);
+ }
return rval;
}
-struct flow *
-get_flow(void)
-{
- struct flow *flow;
-
- MALLOC(flow, struct flow *, sizeof(struct flow), M_TDB, M_WAITOK);
- bzero(flow, sizeof(struct flow));
-
- ipsec_in_use++;
- return flow;
-}
-
/*
* Called at splsoftclock().
*/
@@ -695,18 +451,23 @@ handle_expirations(void *arg)
if ((tdb->tdb_flags & TDBF_TIMER) &&
(tdb->tdb_exp_timeout <= time.tv_sec))
{
- /* If it's an "invalid" TDB, do a silent expiration */
- if (!(tdb->tdb_flags & TDBF_INVALID))
+ /*
+ * If it's an "invalid" TDB or one that hasn't been used
+ * before, do a silent expiration.
+ */
+ if ((!(tdb->tdb_flags & TDBF_INVALID)) && tdb->tdb_first_use)
pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, 0);
+ tdb_delete(tdb, 0);
continue;
}
else
if ((tdb->tdb_flags & TDBF_FIRSTUSE) &&
(tdb->tdb_first_use + tdb->tdb_exp_first_use <= time.tv_sec))
{
- pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
- tdb_delete(tdb, 0, 0);
+ /* If the TDB hasn't been used, don't renew it */
+ if (tdb->tdb_first_use != 0)
+ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_HARD);
+ tdb_delete(tdb, 0);
continue;
}
@@ -714,7 +475,9 @@ handle_expirations(void *arg)
if ((tdb->tdb_flags & TDBF_SOFT_TIMER) &&
(tdb->tdb_soft_timeout <= time.tv_sec))
{
- pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
+ /* If the TDB hasn't been used, don't renew it */
+ if (tdb->tdb_first_use != 0)
+ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
tdb_expiration(tdb, TDBEXP_EARLY);
}
@@ -723,7 +486,9 @@ handle_expirations(void *arg)
(tdb->tdb_first_use + tdb->tdb_soft_first_use <=
time.tv_sec))
{
- pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
+ /* If the TDB hasn't been used, don't renew it */
+ if (tdb->tdb_first_use != 0)
+ pfkeyv2_expire(tdb, SADB_EXT_LIFETIME_SOFT);
tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE;
tdb_expiration(tdb, TDBEXP_EARLY);
}
@@ -746,37 +511,27 @@ tdb_expiration(struct tdb *tdb, int flags)
u_int64_t next_timeout = 0;
int s = spltdb();
- /*
- * If this is the local use SPI, this is an SPD entry, so don't setup any
- * timers.
- */
- if (ntohl(tdb->tdb_spi) == SPI_LOCAL_USE)
- {
- splx(s);
- return;
- }
-
/* Find the earliest expiration. */
if ((tdb->tdb_flags & TDBF_FIRSTUSE) && tdb->tdb_first_use != 0 &&
(next_timeout == 0 ||
next_timeout > tdb->tdb_first_use + tdb->tdb_exp_first_use))
- next_timeout = tdb->tdb_first_use + tdb->tdb_exp_first_use;
+ next_timeout = tdb->tdb_first_use + tdb->tdb_exp_first_use;
if ((tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) && tdb->tdb_first_use != 0 &&
(next_timeout == 0 ||
next_timeout > tdb->tdb_first_use + tdb->tdb_soft_first_use))
- next_timeout = tdb->tdb_first_use + tdb->tdb_soft_first_use;
+ next_timeout = tdb->tdb_first_use + tdb->tdb_soft_first_use;
if ((tdb->tdb_flags & TDBF_TIMER) &&
(next_timeout == 0 || next_timeout > tdb->tdb_exp_timeout))
- next_timeout = tdb->tdb_exp_timeout;
+ next_timeout = tdb->tdb_exp_timeout;
if ((tdb->tdb_flags & TDBF_SOFT_TIMER) &&
(next_timeout == 0 || next_timeout > tdb->tdb_soft_timeout))
- next_timeout = tdb->tdb_soft_timeout;
+ next_timeout = tdb->tdb_soft_timeout;
/* No change? */
if (next_timeout == tdb->tdb_timeout)
{
- splx(s);
- return;
+ splx(s);
+ return;
}
/*
@@ -824,6 +579,7 @@ tdb_expiration(struct tdb *tdb, int flags)
TAILQ_REMOVE(&expclusterlist, tdb, tdb_expnext);
tdb->tdb_expnext.tqe_prev = NULL;
}
+
TAILQ_REMOVE(&explist, tdb, tdb_explink);
}
@@ -831,8 +587,8 @@ tdb_expiration(struct tdb *tdb, int flags)
if (next_timeout == 0)
{
- splx(s);
- return;
+ splx(s);
+ return;
}
/*
@@ -902,22 +658,26 @@ tdb_expiration(struct tdb *tdb, int flags)
"expclusterlist last link out of order (%p, %p)",
tdb, t);
}
+
t = TAILQ_FIRST(&explist);
if (t != NULL && t->tdb_timeout > tdb->tdb_timeout)
panic("tdb_expiration: explist first link out of order (%p, %p)", tdb,
t);
+
t = TAILQ_PREV(tdb, explist_head, tdb_explink);
if (t != NULL && t->tdb_timeout > tdb->tdb_timeout)
panic("tdb_expiration: explist prev link out of order (%p, %p)", tdb, t);
else if (t == NULL && tdb != TAILQ_FIRST(&explist))
panic("tdb_expiration: explist first link out of order (%p, %p)", tdb,
TAILQ_FIRST(&explist));
+
t = TAILQ_NEXT(tdb, tdb_explink);
if (t != NULL && t->tdb_timeout < tdb->tdb_timeout)
panic("tdb_expiration: explist next link out of order (%p, %p)", tdb, t);
else if (t == NULL && tdb != TAILQ_LAST(&explist, explist_head))
panic("tdb_expiration: explist last link out of order (%p, %p)", tdb,
TAILQ_LAST(&explist, explist_head));
+
t = TAILQ_LAST(&explist, explist_head);
if (t != tdb && t->tdb_timeout < tdb->tdb_timeout)
panic("tdb_expiration: explist last link out of order (%p, %p)", tdb, t);
@@ -927,86 +687,64 @@ tdb_expiration(struct tdb *tdb, int flags)
}
/*
- * Caller is responsible for setting at least spltdb().
- */
-struct flow *
-find_flow(union sockaddr_union *src, union sockaddr_union *srcmask,
- union sockaddr_union *dst, union sockaddr_union *dstmask,
- u_int8_t proto, struct tdb *tdb, int ingress)
-{
- struct flow *flow;
-
- if (ingress)
- flow = tdb->tdb_access;
- else
- flow = tdb->tdb_flow;
-
- for (; flow; flow = flow->flow_next)
- if (!bcmp(&src->sa, &flow->flow_src.sa, SA_LEN(&src->sa)) &&
- !bcmp(&dst->sa, &flow->flow_dst.sa, SA_LEN(&dst->sa)) &&
- !bcmp(&srcmask->sa, &flow->flow_srcmask.sa, SA_LEN(&srcmask->sa)) &&
- !bcmp(&dstmask->sa, &flow->flow_dstmask.sa, SA_LEN(&dstmask->sa)) &&
- (proto == flow->flow_proto))
- return flow;
-
- return (struct flow *) NULL;
-}
-
-/*
- * Caller is responsible for setting at least spltdb().
- */
-struct flow *
-find_global_flow(union sockaddr_union *src, union sockaddr_union *srcmask,
- union sockaddr_union *dst, union sockaddr_union *dstmask,
- u_int8_t proto)
-{
- struct flow *flow;
- struct tdb *tdb;
- int i;
-
- if (tdbh == NULL)
- return (struct flow *) NULL;
-
- if (tdb_bypass != NULL)
- if ((flow = find_flow(src, srcmask, dst, dstmask, proto,
- tdb_bypass, FLOW_EGRESS)) != (struct flow *) NULL)
- return flow;
-
- for (i = 0; i <= tdb_hashmask; i++)
- {
- for (tdb = tdbh[i]; tdb != NULL; tdb = tdb->tdb_hnext)
- if ((flow = find_flow(src, srcmask, dst, dstmask, proto,
- tdb, FLOW_EGRESS)) != (struct flow *) NULL)
- return flow;
- }
- return (struct flow *) NULL;
-}
-
-/*
* Caller is responsible for spltdb().
*/
void
tdb_rehash(void)
{
- struct tdb **new_tdbh, *tdbp, *tdbnp;
+ struct tdb **new_tdbh, **new_tdbaddr, **new_srcaddr, *tdbp, *tdbnp;
u_int i, old_hashmask = tdb_hashmask;
u_int32_t hashval;
tdb_hashmask = (tdb_hashmask << 1) | 1;
+
MALLOC(new_tdbh, struct tdb **, sizeof(struct tdb *) * (tdb_hashmask + 1),
M_TDB, M_WAITOK);
+ MALLOC(new_tdbaddr, struct tdb **,
+ sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK);
+ MALLOC(new_srcaddr, struct tdb **,
+ sizeof(struct tdb *) * (tdb_hashmask + 1), M_TDB, M_WAITOK);
+
bzero(new_tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1));
+ bzero(new_tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
+ bzero(new_srcaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
+
for (i = 0; i <= old_hashmask; i++)
- for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp)
- {
- tdbnp = tdbp->tdb_hnext;
- hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto);
- tdbp->tdb_hnext = new_tdbh[hashval];
- new_tdbh[hashval] = tdbp;
- }
+ {
+ for (tdbp = tdbh[i]; tdbp != NULL; tdbp = tdbnp)
+ {
+ tdbnp = tdbp->tdb_hnext;
+ hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst,
+ tdbp->tdb_sproto);
+ tdbp->tdb_hnext = new_tdbh[hashval];
+ new_tdbh[hashval] = tdbp;
+ }
+
+ for (tdbp = tdbaddr[i]; tdbp != NULL; tdbp = tdbnp)
+ {
+ tdbnp = tdbp->tdb_anext;
+ hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto);
+ tdbp->tdb_anext = new_tdbaddr[hashval];
+ new_tdbaddr[hashval] = tdbp;
+ }
+
+ for (tdbp = tdbsrc[i]; tdbp != NULL; tdbp = tdbnp)
+ {
+ tdbnp = tdbp->tdb_snext;
+ hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto);
+ tdbp->tdb_snext = new_srcaddr[hashval];
+ new_srcaddr[hashval] = tdbp;
+ }
+ }
FREE(tdbh, M_TDB);
tdbh = new_tdbh;
+
+ FREE(tdbaddr, M_TDB);
+ tdbaddr = new_tdbaddr;
+
+ FREE(tdbsrc, M_TDB);
+ tdbsrc = new_srcaddr;
}
/*
@@ -1022,7 +760,16 @@ puttdb(struct tdb *tdbp)
{
MALLOC(tdbh, struct tdb **, sizeof(struct tdb *) * (tdb_hashmask + 1),
M_TDB, M_WAITOK);
+ MALLOC(tdbaddr, struct tdb **,
+ sizeof(struct tdb *) * (tdb_hashmask + 1),
+ M_TDB, M_WAITOK);
+ MALLOC(tdbsrc, struct tdb **,
+ sizeof(struct tdb *) * (tdb_hashmask + 1),
+ M_TDB, M_WAITOK);
+
bzero(tdbh, sizeof(struct tdb *) * (tdb_hashmask + 1));
+ bzero(tdbaddr, sizeof(struct tdb *) * (tdb_hashmask + 1));
+ bzero(tdbsrc, sizeof(struct tdb *) * (tdb_hashmask + 1));
}
hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto);
@@ -1040,82 +787,37 @@ puttdb(struct tdb *tdbp)
tdb_rehash();
hashval = tdb_hash(tdbp->tdb_spi, &tdbp->tdb_dst, tdbp->tdb_sproto);
}
+
tdbp->tdb_hnext = tdbh[hashval];
tdbh[hashval] = tdbp;
- tdb_count++;
- splx(s);
-}
-/*
- * Caller is responsible for setting at least spltdb().
- */
-void
-put_flow(struct flow *flow, struct tdb *tdb, int ingress)
-{
- if (ingress)
- {
- flow->flow_next = tdb->tdb_access;
- tdb->tdb_access = flow;
- }
- else
- {
- flow->flow_next = tdb->tdb_flow;
- tdb->tdb_flow = flow;
- }
+ hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto);
+ tdbp->tdb_anext = tdbaddr[hashval];
+ tdbaddr[hashval] = tdbp;
- if (flow->flow_next)
- flow->flow_next->flow_prev = flow;
+ hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto);
+ tdbp->tdb_snext = tdbsrc[hashval];
+ tdbsrc[hashval] = tdbp;
- flow->flow_sa = tdb;
- flow->flow_prev = (struct flow *) NULL;
-}
-
-/*
- * Caller is responsible for setting at least spltdb().
- */
-void
-delete_flow(struct flow *flow, struct tdb *tdb, int ingress)
-{
- if (tdb)
- {
- if (ingress && (tdb->tdb_access == flow))
- tdb->tdb_access = flow->flow_next;
- else
- if (!ingress && (tdb->tdb_flow == flow))
- tdb->tdb_flow = flow->flow_next;
-
- if (flow->flow_prev)
- flow->flow_prev->flow_next = flow->flow_next;
-
- if (flow->flow_next)
- flow->flow_next->flow_prev = flow->flow_prev;
- }
+ tdb_count++;
- if (!ingress)
- ipsec_in_use--;
+ ipsec_last_added = time.tv_sec;
- FREE(flow, M_TDB);
+ splx(s);
}
/*
* Caller is responsible to set at least spltdb().
*/
void
-tdb_delete(struct tdb *tdbp, int delchain, int expflags)
+tdb_delete(struct tdb *tdbp, int expflags)
{
- struct tdb *tdbpp, *tdbpn;
+ struct ipsec_policy *ipo;
+ struct tdb *tdbpp;
struct inpcb *inp;
- u_int32_t hashval = tdbp->tdb_sproto + tdbp->tdb_spi;
+ u_int32_t hashval;
int s;
- /* When deleting the bypass tdb, skip the hash table code. */
- if (tdbp == tdb_bypass && tdbp != NULL)
- {
- s = spltdb();
- delchain = 0;
- goto skip_hash;
- }
-
if (tdbh == NULL)
return;
@@ -1138,122 +840,44 @@ tdb_delete(struct tdb *tdbp, int delchain, int expflags)
tdbp->tdb_hnext = NULL;
- skip_hash:
- /*
- * If there was something before us in the chain pointing to us,
- * make it point nowhere.
- */
- if ((tdbp->tdb_inext) &&
- (tdbp->tdb_inext->tdb_onext == tdbp))
- tdbp->tdb_inext->tdb_onext = NULL;
-
- /*
- * If there was something after us in the chain pointing to us,
- * make it point nowhere.
- */
- if ((tdbp->tdb_onext) &&
- (tdbp->tdb_onext->tdb_inext == tdbp))
- tdbp->tdb_onext->tdb_inext = NULL;
-
- tdbpn = tdbp->tdb_onext;
- tdbp->tdb_inext = tdbp->tdb_onext = NULL;
+ hashval = tdb_hash(0, &tdbp->tdb_dst, tdbp->tdb_sproto);
- if (tdbp->tdb_xform)
+ if (tdbaddr[hashval] == tdbp)
{
- (*(tdbp->tdb_xform->xf_zeroize))(tdbp);
- tdbp->tdb_xform = NULL;
+ tdbpp = tdbp;
+ tdbaddr[hashval] = tdbp->tdb_anext;
}
+ else
+ for (tdbpp = tdbaddr[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_anext)
+ if (tdbpp->tdb_anext == tdbp)
+ {
+ tdbpp->tdb_anext = tdbp->tdb_anext;
+ tdbpp = tdbp;
+ break;
+ }
- while (tdbp->tdb_access)
- delete_flow(tdbp->tdb_access, tdbp, FLOW_INGRESS);
+ hashval = tdb_hash(0, &tdbp->tdb_src, tdbp->tdb_sproto);
- while (tdbp->tdb_flow)
+ if (tdbsrc[hashval] == tdbp)
{
- /* Delete the flow and the routing entry that goes with it. */
- struct sockaddr_encap encapdst, encapnetmask;
-
- bzero(&encapdst, sizeof(struct sockaddr_encap));
- bzero(&encapnetmask, sizeof(struct sockaddr_encap));
-
- encapdst.sen_family = PF_KEY;
- encapnetmask.sen_family = PF_KEY;
-
- switch (tdbp->tdb_flow->flow_src.sa.sa_family)
+ tdbpp = tdbp;
+ tdbsrc[hashval] = tdbp->tdb_snext;
+ }
+ else
+ for (tdbpp = tdbsrc[hashval]; tdbpp != NULL; tdbpp = tdbpp->tdb_snext)
+ if (tdbpp->tdb_snext == tdbp)
{
- case AF_INET:
- encapdst.sen_len = SENT_IP4_LEN;
- encapdst.sen_type = SENT_IP4;
- encapdst.sen_ip_src = tdbp->tdb_flow->flow_src.sin.sin_addr;
- encapdst.sen_ip_dst = tdbp->tdb_flow->flow_dst.sin.sin_addr;
- encapdst.sen_proto = tdbp->tdb_flow->flow_proto;
- encapdst.sen_sport = tdbp->tdb_flow->flow_src.sin.sin_port;
- encapdst.sen_dport = tdbp->tdb_flow->flow_dst.sin.sin_port;
-
- encapnetmask.sen_ip_src = tdbp->tdb_flow->flow_srcmask.sin.sin_addr;
- encapnetmask.sen_ip_dst = tdbp->tdb_flow->flow_dstmask.sin.sin_addr;
-
- /* Mask transport protocol and ports if applicable */
- if (tdbp->tdb_flow->flow_proto)
- {
- encapnetmask.sen_proto = 0xff;
- if (tdbp->tdb_flow->flow_src.sin.sin_port)
- encapnetmask.sen_sport = 0xffff;
- if (tdbp->tdb_flow->flow_dst.sin.sin_port)
- encapnetmask.sen_dport = 0xffff;
- }
- break;
-
-#if INET6
- case AF_INET6:
- encapdst.sen_len = SENT_IP6_LEN;
- encapdst.sen_type = SENT_IP6;
- encapdst.sen_ip6_src = tdbp->tdb_flow->flow_src.sin6.sin6_addr;
- encapdst.sen_ip6_dst = tdbp->tdb_flow->flow_dst.sin6.sin6_addr;
- encapdst.sen_ip6_proto = tdbp->tdb_flow->flow_proto;
- encapdst.sen_ip6_sport = tdbp->tdb_flow->flow_src.sin6.sin6_port;
- encapdst.sen_ip6_dport = tdbp->tdb_flow->flow_dst.sin6.sin6_port;
-
- encapnetmask.sen_ip6_src = tdbp->tdb_flow->flow_srcmask.sin6.sin6_addr;
- encapnetmask.sen_ip6_dst = tdbp->tdb_flow->flow_dstmask.sin6.sin6_addr;
-
- /* Mask transport protocol and ports if applicable */
- if (tdbp->tdb_flow->flow_proto)
- {
- encapnetmask.sen_ip6_proto = 0xff;
- if (tdbp->tdb_flow->flow_src.sin6.sin6_port)
- encapnetmask.sen_ip6_sport = 0xffff;
- if (tdbp->tdb_flow->flow_dst.sin6.sin6_port)
- encapnetmask.sen_ip6_dport = 0xffff;
- }
- break;
-#endif /* INET6 */
-
- default:
-#ifdef DIAGNOSTIC
- panic("tdb_delete(): SA %s/%08x/%d has flow of unknown type %d", ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi), tdbp->tdb_sproto, tdbp->tdb_flow->flow_src.sa.sa_family);
-#endif /* DIAGNOSTIC */
- delete_flow(tdbp->tdb_flow, tdbp, FLOW_EGRESS);
- continue;
+ tdbpp->tdb_snext = tdbp->tdb_snext;
+ tdbpp = tdbp;
+ break;
}
- /* Always the same type for address and netmask */
- encapnetmask.sen_len = encapdst.sen_len;
- encapnetmask.sen_type = encapdst.sen_type;
-
- rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
- (struct sockaddr *) 0,
- (struct sockaddr *) &encapnetmask,
- 0, (struct rtentry **) 0);
+ tdbp->tdb_snext = NULL;
- delete_flow(tdbp->tdb_flow, tdbp, FLOW_EGRESS);
- }
-
- /* Cleanup SA-Bindings */
- for (tdbpp = TAILQ_FIRST(&tdbp->tdb_bind_in); tdbpp;
- tdbpp = TAILQ_FIRST(&tdbp->tdb_bind_in))
+ if (tdbp->tdb_xform)
{
- TAILQ_REMOVE(&tdbpp->tdb_bind_in, tdbpp, tdb_bind_in_next);
- tdbpp->tdb_bind_out = NULL;
+ (*(tdbp->tdb_xform->xf_zeroize))(tdbp);
+ tdbp->tdb_xform = NULL;
}
/* Cleanup inp references */
@@ -1264,8 +888,13 @@ tdb_delete(struct tdb *tdbp, int delchain, int expflags)
inp->inp_tdb = NULL;
}
- if (tdbp->tdb_bind_out)
- TAILQ_REMOVE(&tdbp->tdb_bind_out->tdb_bind_in, tdbp, tdb_bind_in_next);
+ /* Cleanup SPD references */
+ for (ipo = TAILQ_FIRST(&tdbp->tdb_policy_head); ipo;
+ ipo = TAILQ_FIRST(&tdbp->tdb_policy_head))
+ {
+ TAILQ_REMOVE(&tdbp->tdb_policy_head, ipo, ipo_tdb_next);
+ ipo->ipo_tdb = NULL;
+ }
/* Remove us from the expiration lists. */
if (tdbp->tdb_timeout != 0)
@@ -1287,16 +916,9 @@ tdb_delete(struct tdb *tdbp, int delchain, int expflags)
tdbp->tdb_dstid = NULL;
}
- /* If we're deleting the bypass tdb, reset the variable. */
- if (tdbp == tdb_bypass)
- tdb_bypass = NULL;
-
FREE(tdbp, M_TDB);
tdb_count--;
- if (delchain && tdbpn)
- tdb_delete(tdbpn, delchain, expflags);
-
splx(s);
}
@@ -1313,9 +935,10 @@ tdb_init(struct tdb *tdbp, u_int16_t alg, struct ipsecinit *ii)
tdbp->tdb_epoch = kernfs_epoch - 1;
/* Init Incoming SA-Binding Queues */
- TAILQ_INIT(&tdbp->tdb_bind_in);
TAILQ_INIT(&tdbp->tdb_inp);
+ TAILQ_INIT(&tdbp->tdb_policy_head);
+
for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
if (xsp->xf_type == alg)
return (*(xsp->xf_init))(tdbp, xsp, ii);
@@ -1334,20 +957,26 @@ int
ipsp_kern(int off, char **bufp, int len)
{
static char buffer[IPSEC_KERNFS_BUFSIZE];
- struct flow *flow;
- struct tdb *tdb, *tdbp;
+ struct tdb *tdb;
int l, i, s;
- if (off == 0)
- kernfs_epoch++;
-
- if (bufp == NULL || tdbh == NULL)
+ if (bufp == NULL)
return 0;
bzero(buffer, IPSEC_KERNFS_BUFSIZE);
-
*bufp = buffer;
+
+ if (off == 0)
+ {
+ kernfs_epoch++;
+ l = sprintf(buffer, "Hashmask: %d, policy entries: %d\n", tdb_hashmask,
+ ipsec_in_use);
+ return l;
+ }
+ if (tdbh == NULL)
+ return 0;
+
for (i = 0; i <= tdb_hashmask; i++)
{
s = spltdb();
@@ -1478,49 +1107,6 @@ ipsp_kern(int off, char **bufp, int len)
l += sprintf(buffer + l, "\tAssociated interface = <%s>\n",
((struct ifnet *) tdb->tdb_interface)->if_xname);
- if (tdb->tdb_bind_out)
- l += sprintf(buffer + l,
- "\tBound SA: SPI = %08x, "
- "Destination = %s, Sproto = %u\n",
- ntohl(tdb->tdb_bind_out->tdb_spi),
- ipsp_address(tdb->tdb_bind_out->tdb_dst),
- tdb->tdb_bind_out->tdb_sproto);
- for (i = 0, tdbp = TAILQ_FIRST(&tdb->tdb_bind_in); tdbp;
- tdbp = TAILQ_NEXT(tdbp, tdb_bind_in_next))
- i++;
-
- if (i > 0)
- l += sprintf(buffer + l,
- "\tReferenced by %d incoming SA%s\n",
- i, i == 1 ? "" : "s");
-
- if (tdb->tdb_onext)
- l += sprintf(buffer + l,
- "\tNext SA: SPI = %08x, "
- "Destination = %s, Sproto = %u\n",
- ntohl(tdb->tdb_onext->tdb_spi),
- ipsp_address(tdb->tdb_onext->tdb_dst),
- tdb->tdb_onext->tdb_sproto);
-
- if (tdb->tdb_inext)
- l += sprintf(buffer + l,
- "\tPrevious SA: SPI = %08x, "
- "Destination = %s, Sproto = %u\n",
- ntohl(tdb->tdb_inext->tdb_spi),
- ipsp_address(tdb->tdb_inext->tdb_dst),
- tdb->tdb_inext->tdb_sproto);
-
- for (i = 0, flow = tdb->tdb_flow; flow; flow = flow->flow_next)
- i++;
-
- l+= sprintf(buffer + l, "\tCurrently used by %d flows\n", i);
-
- for (i = 0, flow = tdb->tdb_access; flow; flow = flow->flow_next)
- i++;
-
- l+= sprintf(buffer + l,
- "\t%d ingress flows specified\n", i);
-
l += sprintf(buffer + l, "\t%u flows have used this SA\n",
tdb->tdb_cur_allocations);
@@ -1603,696 +1189,87 @@ ipsp_kern(int off, char **bufp, int len)
return 0;
}
-char *
-inet_ntoa4(struct in_addr ina)
-{
- static char buf[4][4 * sizeof "123" + 4];
- unsigned char *ucp = (unsigned char *) &ina;
- static int i = 3;
-
- i = (i + 1) % 4;
- sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff,
- ucp[2] & 0xff, ucp[3] & 0xff);
- return (buf[i]);
-}
-
-char *
-ipsp_address(union sockaddr_union sa)
-{
- switch (sa.sa.sa_family)
- {
- case AF_INET:
- return inet_ntoa4(sa.sin.sin_addr);
-
-#if INET6
- case AF_INET6:
- return ip6_sprintf(&sa.sin6.sin6_addr);
-#endif /* INET6 */
-
- default:
- return "(unknown address family)";
- }
-}
-
/*
- * Loop over a tdb chain, taking into consideration protocol tunneling. The
- * fourth argument is set if the first encapsulation header is already in
- * place.
+ * Check which transformations are required.
*/
-int
-ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
+u_int8_t
+get_sa_require(struct inpcb *inp)
{
- int i, off, error;
- struct mbuf *mp;
-
-#ifdef INET
- struct ip *ip;
-#endif /* INET */
-#ifdef INET6
- struct ip6_hdr *ip6;
-#endif /* INET6 */
-
- /* Check that the transform is allowed by the administrator */
- if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
- (tdb->tdb_sproto == IPPROTO_AH && !ah_enable))
- {
- DPRINTF(("ipsp_process_packet(): IPSec outbound packet dropped due to policy\n"));
- m_freem(m);
- return EHOSTUNREACH;
- }
-
- /* Sanity check */
- if (!tdb->tdb_xform)
- {
- DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
- m_freem(m);
- return EHOSTUNREACH;
- }
-
- /* Check if the SPI is invalid */
- if (tdb->tdb_flags & TDBF_INVALID)
- {
- DPRINTF(("ipsp_process_packet(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
- m_freem(m);
- return ENXIO;
- }
-
- /* Check that the network protocol is supported */
- switch (tdb->tdb_dst.sa.sa_family)
- {
-#ifdef INET
- case AF_INET:
- break;
-#endif /* INET */
-
-#ifdef INET6
- case AF_INET6:
- break;
-#endif /* INET6 */
-
- default:
- DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
- m_freem(m);
- return ENXIO;
- }
-
- /* Register first use if applicable, setup relevant expiration timer */
- if (tdb->tdb_first_use == 0)
- {
- tdb->tdb_first_use = time.tv_sec;
- tdb_expiration(tdb, TDBEXP_TIMEOUT);
- }
-
- /*
- * Check for tunneling if we don't have the first header in place.
- * When doing Ethernet-over-IP, we are handed an already-encapsulated
- * frame, so we don't need to re-encapsulate.
- */
- if (tunalready == 0)
+ u_int8_t sareq = 0;
+
+ if (inp != NULL)
{
- /*
- * If the target protocol family is different, we know we'll be
- * doing tunneling.
- */
- if (af == tdb->tdb_dst.sa.sa_family)
- {
-#ifdef INET
- if (af == AF_INET)
- i = sizeof(struct ip);
-#endif /* INET */
-
-#ifdef INET6
- if (af == AF_INET6)
- i = sizeof(struct ip6_hdr);
-#endif /* INET6 */
-
- /* Bring the network header in the first mbuf */
- if (m->m_len < i)
- {
- if ((m = m_pullup(m, i)) == 0)
- return ENOBUFS;
- }
-
-#ifdef INET
- ip = mtod(m, struct ip *);
-#endif /* INET */
-
-#ifdef INET6
- ip6 = mtod(m, struct ip6_hdr *);
-#endif /* INET6 */
- }
-
- /* Do the appropriate encapsulation, if necessary */
- if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
- (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling requested */
- (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
-#ifdef INET
- ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
- (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
-#endif /* INET */
-#ifdef INET6
- ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
- (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
- (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
- &ip6->ip6_dst))) ||
-#endif /* INET6 */
- 0)
- {
-#ifdef INET
- /* Fix IPv4 header checksum and length */
- if (af == AF_INET)
- {
- if ((m = m_pullup(m, sizeof(struct ip))) == 0)
- return ENOBUFS;
-
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
- }
-#endif /* INET */
-
-#ifdef INET6
- /* Fix IPv6 header payload length */
- if (af == AF_INET6)
- {
- if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0)
- return ENOBUFS;
-
- if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
- /* no jumbogram support */
- m_freem(m);
- return ENXIO; /*?*/
- }
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
- }
-#endif /* INET6 */
-
- /* Encapsulate -- the last two arguments are unused */
- error = ipip_output(m, tdb, &mp, 0, 0);
- if ((mp == NULL) && (!error))
- error = EFAULT;
- if (error)
- {
- if (mp)
- {
- m_freem(mp);
- mp = NULL;
- }
-
- return error;
- }
-
- m = mp;
- mp = NULL;
- }
-
- /* We may be done with this TDB */
- if (tdb->tdb_xform->xf_type == XF_IP4)
- return ipsp_process_done(m, tdb);
+ sareq |= inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_AUTH : 0;
+ sareq |= inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_CONF : 0;
+ sareq |= inp->inp_seclevel[SL_ESP_NETWORK] >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_TUNNEL : 0;
}
else
{
- /*
- * If this is just an IP-IP TDB and we're told there's already an
- * encapsulation header, move on.
- */
- if (tdb->tdb_xform->xf_type == XF_IP4)
- return ipsp_process_done(m, tdb);
- }
-
- /* Extract some information off the headers */
- switch (tdb->tdb_dst.sa.sa_family)
- {
-#ifdef INET
- case AF_INET:
- ip = mtod(m, struct ip *);
- i = ip->ip_hl << 2;
- off = offsetof(struct ip, ip_p);
- break;
-#endif /* INET */
-
-#ifdef INET6
- case AF_INET6:
- ip6 = mtod(m, struct ip6_hdr *);
- i = sizeof(struct ip6_hdr);
- off = offsetof(struct ip6_hdr, ip6_nxt);
- break;
-#endif /* INET6 */
+ sareq |= ipsec_auth_default_level >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_AUTH : 0;
+ sareq |= ipsec_esp_trans_default_level >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_CONF : 0;
+ sareq |= ipsec_esp_network_default_level >= IPSEC_LEVEL_USE ?
+ NOTIFY_SATYPE_TUNNEL : 0;
}
-
- /* Invoke the IPsec transform */
- return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
+
+ return (sareq);
}
/*
- * Called by the IPsec output transform callbacks, to transmit the packet
- * or do further processing, as necessary.
+ * Add an inpcb to the list of inpcb which reference this tdb directly.
*/
-int
-ipsp_process_done(struct mbuf *m, struct tdb *tdb)
+void
+tdb_add_inp(struct tdb *tdb, struct inpcb *inp)
{
-#ifdef INET
- struct ip *ip;
-#endif /* INET */
-
-#ifdef INET6
- struct ip6_hdr *ip6;
-#endif /* INET6 */
-
- switch (tdb->tdb_dst.sa.sa_family)
+ if (inp->inp_tdb)
{
-#ifdef INET
- case AF_INET:
- /* Fix the header length, for AH processing */
- if (tdb->tdb_dst.sa.sa_family == AF_INET)
- {
- ip = mtod(m, struct ip *);
- ip->ip_len = htons(m->m_pkthdr.len);
- }
- break;
-#endif /* INET */
-
-#ifdef INET6
- case AF_INET6:
- /* Fix the header length, for AH processing */
- if (tdb->tdb_dst.sa.sa_family == AF_INET6)
- {
- if (m->m_pkthdr.len < sizeof(*ip6)) {
- m_freem(m);
- return ENXIO;
- }
- if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
- /* no jumbogram support */
- m_freem(m);
- return ENXIO; /*?*/
- }
- ip6 = mtod(m, struct ip6_hdr *);
- ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
- }
- break;
-#endif /* INET6 */
+ if (inp->inp_tdb == tdb)
+ return;
- default:
- m_freem(m);
- DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
- tdb->tdb_dst.sa.sa_family));
- return ENXIO;
+ TAILQ_REMOVE(&inp->inp_tdb->tdb_inp, inp, inp_tdb_next);
}
- /* If there's another TDB to apply, do so. */
- if (tdb->tdb_onext)
- return ipsp_process_packet(m, tdb->tdb_onext,
- tdb->tdb_onext->tdb_dst.sa.sa_family, 0);
-
- /*
- * If we're done with IPsec processing, transmit the packet using the
- * appropriate network protocol (IP or IPv6).
- */
- switch (tdb->tdb_dst.sa.sa_family)
- {
-#ifdef INET
- case AF_INET:
- NTOHS(ip->ip_len);
- NTOHS(ip->ip_off);
-
- return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT,
- NULL, NULL);
-#endif /* INET */
-
-#ifdef INET6
- case AF_INET6:
- /*
- * we don't need massage, IPv6 header fields are always in
- * net endian
- */
- return ip6_output(m, NULL, NULL, IPV6_ENCAPSULATED, NULL, NULL);
-#endif /* INET6 */
- }
+ inp->inp_tdb = tdb;
+ TAILQ_INSERT_TAIL(&tdb->tdb_inp, inp, inp_tdb_next);
- /* Not reached */
- return EINVAL;
+ DPRINTF(("tdb_add_inp: tdb: %p, inp: %p\n", tdb, inp));
}
-/*
- * Lookup at the SPD based on the headers contained on the mbuf. The second
- * argument indicates what protocol family the header at the beginning of
- * the mbuf is. hlen is the the offset of the transport protocol header
- * in the mbuf.
- *
- * Return combinations (of return value and in *error):
- * - NULL/0 -> no IPsec required on packet
- * - NULL/-EINVAL -> silently drop the packet
- * - NULL/errno -> drop packet and return error
- * or a valid TDB value.
- */
-struct tdb *
-ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error)
+/* Return a printable string for the IPv4 address. */
+char *
+inet_ntoa4(struct in_addr ina)
{
- struct sockaddr_encap *ddst, *gw;
- struct route_enc re0, *re = &re0;
- union sockaddr_union sunion;
- struct tdb *tdb, tdb2;
-
- /*
- * If there are no flows in place, there's no point
- * continuing with the SPD lookup.
- */
- if (!ipsec_in_use)
- {
- *error = 0;
- return NULL;
- }
-
- bzero((caddr_t) re, sizeof(*re));
- ddst = (struct sockaddr_encap *) &re->re_dst;
- ddst->sen_family = PF_KEY;
+ static char buf[4][4 * sizeof "123" + 4];
+ unsigned char *ucp = (unsigned char *) &ina;
+ static int i = 3;
+
+ i = (i + 1) % 4;
+ sprintf(buf[i], "%d.%d.%d.%d", ucp[0] & 0xff, ucp[1] & 0xff,
+ ucp[2] & 0xff, ucp[3] & 0xff);
+ return (buf[i]);
+}
- /*
- * Do an SPD lookup -- this code should probably be moved
- * to a separate function.
- */
- switch (af)
+/* Return a printable string for the address. */
+char *
+ipsp_address(union sockaddr_union sa)
+{
+ switch (sa.sa.sa_family)
{
-#ifdef INET
+#if INET
case AF_INET:
- ddst->sen_len = SENT_IP4_LEN;
- ddst->sen_type = SENT_IP4;
- m_copydata(m, offsetof(struct ip, ip_src),
- sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_src));
- m_copydata(m, offsetof(struct ip, ip_dst),
- sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_dst));
- m_copydata(m, offsetof(struct ip, ip_p), sizeof(u_int8_t),
- (caddr_t) &(ddst->sen_proto));
-
- /* If TCP/UDP, extract the port numbers to use in the lookup */
- switch (ddst->sen_proto)
- {
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- /*
- * Luckily, the offset of the src/dst ports in both the UDP
- * and TCP headers is the same (first two 16-bit values
- * in the respective headers), so we can just copy them.
- */
- m_copydata(m, hlen, sizeof(u_int16_t),
- (caddr_t) &(ddst->sen_sport));
- m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
- (caddr_t) &(ddst->sen_dport));
- break;
-
- default:
- ddst->sen_sport = 0;
- ddst->sen_dport = 0;
- }
-
- break;
+ return inet_ntoa4(sa.sin.sin_addr);
#endif /* INET */
-#ifdef INET6
+#if INET6
case AF_INET6:
- ddst->sen_len = SENT_IP6_LEN;
- ddst->sen_type = SENT_IP6;
- m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
- sizeof(struct in6_addr),
- (caddr_t) &(ddst->sen_ip6_src));
- m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
- sizeof(struct in6_addr),
- (caddr_t) &(ddst->sen_ip6_dst));
- m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt), sizeof(u_int8_t),
- (caddr_t) &(ddst->sen_ip6_proto));
-
- /* If TCP/UDP, extract the port numbers to use in the lookup */
- switch (ddst->sen_ip6_proto)
- {
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- /*
- * Luckily, the offset of the src/dst ports in both the UDP
- * and TCP headers is the same (first two 16-bit values
- * in the respective headers), so we can just copy them.
- */
- m_copydata(m, hlen, sizeof(u_int16_t),
- (caddr_t) &(ddst->sen_ip6_sport));
- m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
- (caddr_t) &(ddst->sen_ip6_dport));
- break;
-
- default:
- ddst->sen_ip6_sport = 0;
- ddst->sen_ip6_dport = 0;
- }
-
- break;
-#endif /* INET6 */
-
- default:
- *error = EAFNOSUPPORT;
- return NULL;
- }
-
- /* Actual SPD lookup */
- rtalloc((struct route *) re);
- if (re->re_rt == NULL)
- {
- *error = 0;
- return NULL; /* Nothing found */
- }
-
- bzero(&sunion, sizeof(sunion));
- gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
-
- /* Sanity check */
- if (gw == NULL || ((gw->sen_type != SENT_IPSP) &&
- (gw->sen_type != SENT_IPSP6)))
- {
- DPRINTF(("ipsp_spd_lookup(): no gw, or gw data not IPSP (%d)\n",
- gw->sen_type));
-
- if (re->re_rt)
- RTFREE(re->re_rt);
- *error = EHOSTUNREACH;
- return NULL;
- }
-
- /*
- * There might be a specific route, that tells us to avoid
- * doing IPsec; this is useful for specific routes that we
- * don't want to have IPsec applied on, like the key
- * management ports.
- */
- switch (gw->sen_type)
- {
-#ifdef INET
- case SENT_IPSP:
- if ((gw->sen_ipsp_sproto == 0) && (gw->sen_ipsp_spi == 0) &&
- (gw->sen_ipsp_dst.s_addr == 0))
- {
- *error = 0;
- return NULL;
- }
-
- sunion.sin.sin_family = AF_INET;
- sunion.sin.sin_len = sizeof(struct sockaddr_in);
- sunion.sin.sin_addr = gw->sen_ipsp_dst;
- tdb = (struct tdb *) gettdb(gw->sen_ipsp_spi, &sunion,
- gw->sen_ipsp_sproto);
- break;
-#endif /* INET */
-
-#ifdef INET6
- case SENT_IPSP6:
- if ((gw->sen_ipsp6_sproto == 0) && (gw->sen_ipsp6_spi == 0) &&
- IN6_IS_ADDR_UNSPECIFIED(&gw->sen_ipsp6_dst))
- {
- *error = 0;
- return NULL;
- }
-
- sunion.sin6.sin6_family = AF_INET6;
- sunion.sin6.sin6_len = sizeof(struct sockaddr_in6);
- sunion.sin6.sin6_addr = gw->sen_ipsp6_dst;
- tdb = (struct tdb *) gettdb(gw->sen_ipsp6_spi, &sunion,
- gw->sen_ipsp6_sproto);
- break;
+ return ip6_sprintf(&sa.sin6.sin6_addr);
#endif /* INET6 */
default:
- *error = EAFNOSUPPORT;
- return NULL;
- }
-
- /*
- * At this point we have an IPSP "gateway" (tunnel) spec.
- * Use the destination of the tunnel and the SPI to
- * look up the necessary Tunnel Control Block. Look it up,
- * and then pass it, along with the packet and the gw,
- * to the appropriate transformation.
- */
- /* tdb lookup is found up there */
-
- /* Bypass the SA acquisition if that is what we want. */
- if (tdb && tdb->tdb_satype == SADB_X_SATYPE_BYPASS)
- {
- *error = 0;
- return NULL;
- }
-
- /*
- * For VPNs, a route with a reserved SPI is used to
- * indicate the need for an SA when none is established.
- */
- if (((ntohl(gw->sen_ipsp_spi) == SPI_LOCAL_USE) &&
- (gw->sen_type == SENT_IPSP)) ||
- ((ntohl(gw->sen_ipsp6_spi) == SPI_LOCAL_USE) &&
- (gw->sen_type == SENT_IPSP6)))
- {
- if (tdb == NULL)
- {
- /* We will just use system defaults. */
- tdb = &tdb2;
- bzero(&tdb2, sizeof(tdb2));
-
- /* Default entry is for ESP */
- tdb2.tdb_satype = SADB_SATYPE_ESP;
- }
-
- *error = ipsp_acquire_sa(tdb);
- if (*error == 0)
- *error = -EINVAL; /* Silently drop the packet */
- return NULL;
- }
-
- /* Couldn't find the TDB */
- if (tdb == NULL)
- {
-#ifdef INET
- if (gw->sen_type == SENT_IPSP)
- DPRINTF(("ipsp_spd_lookup(): non-existant TDB for SA %s/%08x/%u\n",
- inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi),
- gw->sen_ipsp_sproto));
-#endif /* INET */
-
-#ifdef INET6
- if (gw->sen_type == SENT_IPSP6)
- DPRINTF(("ipsp_spd_lookup(): non-existant TDB for SA %s/%08x/%u\n",
- ip6_sprintf(&gw->sen_ipsp6_dst), ntohl(gw->sen_ipsp6_spi),
- gw->sen_ipsp6_sproto));
-#endif /* INET6 */
-
- *error = EHOSTUNREACH;
- return NULL;
- }
-
- /* Done, IPsec processing necessary */
- *error = 0;
- return tdb;
-}
-
-/*
- * Use PFKEY to acquire an SA.
- */
-int
-ipsp_acquire_sa(struct tdb *tdb)
-{
- /* Check whether Perfect Forward Secrect is required */
- if (ipsec_require_pfs)
- tdb->tdb_flags |= TDBF_PFS;
- else
- tdb->tdb_flags &= ~TDBF_PFS;
-
- /* Initialize expirations */
- if (ipsec_soft_allocations > 0)
- tdb->tdb_soft_allocations = ipsec_soft_allocations;
- else
- tdb->tdb_soft_allocations = 0;
-
- if (ipsec_exp_allocations > 0)
- tdb->tdb_exp_allocations = ipsec_exp_allocations;
- else
- tdb->tdb_exp_allocations = 0;
-
- if (ipsec_soft_bytes > 0)
- tdb->tdb_soft_bytes = ipsec_soft_bytes;
- else
- tdb->tdb_soft_bytes = 0;
-
- if (ipsec_exp_bytes > 0)
- tdb->tdb_exp_bytes = ipsec_exp_bytes;
- else
- tdb->tdb_exp_bytes = 0;
-
- if (ipsec_soft_timeout > 0)
- tdb->tdb_soft_timeout = ipsec_soft_timeout;
- else
- tdb->tdb_soft_timeout = 0;
-
- if (ipsec_exp_timeout > 0)
- tdb->tdb_exp_timeout = ipsec_exp_timeout;
- else
- tdb->tdb_exp_timeout = 0;
-
- if (ipsec_soft_first_use > 0)
- tdb->tdb_soft_first_use = ipsec_soft_first_use;
- else
- tdb->tdb_soft_first_use = 0;
-
- if (ipsec_exp_first_use > 0)
- tdb->tdb_exp_first_use = ipsec_exp_first_use;
- else
- tdb->tdb_exp_first_use = 0;
-
- /*
- * If we don't have an existing desired encryption
- * algorithm, use the default.
- */
- if ((tdb->tdb_encalgxform == NULL) &&
- (tdb->tdb_satype & NOTIFY_SATYPE_CONF))
- {
- if (!strncasecmp(ipsec_def_enc, "des", sizeof("des")))
- tdb->tdb_encalgxform = &enc_xform_des;
- else
- if (!strncasecmp(ipsec_def_enc, "3des",
- sizeof("3des")))
- tdb->tdb_encalgxform = &enc_xform_3des;
- else
- if (!strncasecmp(ipsec_def_enc, "blowfish",
- sizeof("blowfish")))
- tdb->tdb_encalgxform = &enc_xform_blf;
- else
- if (!strncasecmp(ipsec_def_enc, "cast128",
- sizeof("cast128")))
- tdb->tdb_encalgxform = &enc_xform_cast5;
- else
- if (!strncasecmp(ipsec_def_enc, "skipjack",
- sizeof("skipjack")))
- tdb->tdb_encalgxform = &enc_xform_skipjack;
- }
-
- /*
- * If we don't have an existing desired authentication
- * algorithm, use the default.
- */
- if ((tdb->tdb_authalgxform == NULL) &&
- (tdb->tdb_satype & NOTIFY_SATYPE_AUTH))
- {
- if (!strncasecmp(ipsec_def_auth, "hmac-md5",
- sizeof("hmac-md5")))
- tdb->tdb_authalgxform = &auth_hash_hmac_md5_96;
- else
- if (!strncasecmp(ipsec_def_auth, "hmac-sha1",
- sizeof("hmac-sha1")))
- tdb->tdb_authalgxform = &auth_hash_hmac_sha1_96;
- else
- if (!strncasecmp(ipsec_def_auth, "hmac-ripemd160",
- sizeof("hmac_ripemd160")))
- tdb->tdb_authalgxform = &auth_hash_hmac_ripemd_160_96;
+ return "(unknown address family)";
}
-
- /* XXX Initialize src_id/dst_id */
-
- /* PF_KEYv2 notification message */
- return pfkeyv2_acquire(tdb, 0);
}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 450c18ee2e1..6c2dc18231d 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.69 2000/06/18 19:05:49 angelos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.70 2000/09/19 03:20:59 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -6,8 +6,8 @@
* Niels Provos (provos@physnet.uni-hamburg.de) and
* Niklas Hallqvist (niklas@appli.se).
*
- * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
- * in November 1995.
+ * The original version of this code was written by John Ioannidis
+ * for BSD/OS in Athens, Greece, in November 1995.
*
* Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
* by Angelos D. Keromytis.
@@ -55,9 +55,6 @@ union sockaddr_union
struct sockaddr_in6 sin6;
};
-#define FLOW_EGRESS 0
-#define FLOW_INGRESS 1
-
/* HMAC key sizes */
#define MD5HMAC96_KEYSIZE 16
#define SHA1HMAC96_KEYSIZE 20
@@ -91,6 +88,7 @@ union sockaddr_union
#define IPSEC_DEFAULT_EXP_FIRST_USE 7200
#define IPSEC_DEFAULT_DEF_ENC "3des"
#define IPSEC_DEFAULT_DEF_AUTH "hmac-sha1"
+#define IPSEC_DEFAULT_EXPIRE_ACQUIRE 30
struct sockaddr_encap
{
@@ -99,63 +97,47 @@ struct sockaddr_encap
u_int16_t sen_type; /* see SENT_* */
union
{
- u_int8_t Data[16]; /* other stuff mapped here */
-
struct /* SENT_IP4 */
{
+ u_int8_t Direction;
struct in_addr Src;
struct in_addr Dst;
+ u_int8_t Proto;
u_int16_t Sport;
u_int16_t Dport;
- u_int8_t Proto;
- u_int8_t Filler[3];
} Sip4;
struct /* SENT_IP6 */
{
+ u_int8_t Direction;
struct in6_addr Src;
struct in6_addr Dst;
+ u_int8_t Proto;
u_int16_t Sport;
u_int16_t Dport;
- u_int8_t Proto;
- u_int8_t Filler[3];
} Sip6;
- struct /* SENT_IPSP */
- {
- struct in_addr Dst;
- u_int32_t Spi;
- u_int8_t Sproto;
- u_int8_t Filler[7];
- } Sipsp;
-
- struct /* SENT_IPSP6 */
- {
- struct in6_addr Dst;
- u_int32_t Spi;
- u_int8_t Sproto;
- u_int8_t Filler[7];
- } Sipsp6;
+ struct ipsec_policy *PolicyHead; /* SENT_IPSP */
} Sen;
};
+#define IPSP_DIRECTION_IN 0x1
+#define IPSP_DIRECTION_OUT 0x2
+
#define sen_data Sen.Data
#define sen_ip_src Sen.Sip4.Src
#define sen_ip_dst Sen.Sip4.Dst
#define sen_proto Sen.Sip4.Proto
#define sen_sport Sen.Sip4.Sport
#define sen_dport Sen.Sip4.Dport
+#define sen_direction Sen.Sip4.Direction
#define sen_ip6_src Sen.Sip6.Src
#define sen_ip6_dst Sen.Sip6.Dst
#define sen_ip6_proto Sen.Sip6.Proto
#define sen_ip6_sport Sen.Sip6.Sport
#define sen_ip6_dport Sen.Sip6.Dport
-#define sen_ipsp_dst Sen.Sipsp.Dst
-#define sen_ipsp_spi Sen.Sipsp.Spi
-#define sen_ipsp_sproto Sen.Sipsp.Sproto
-#define sen_ipsp6_dst Sen.Sipsp6.Dst
-#define sen_ipsp6_spi Sen.Sipsp6.Spi
-#define sen_ipsp6_sproto Sen.Sipsp6.Sproto
+#define sen_ip6_direction Sen.Sip6.Direction
+#define sen_ipsp Sen.PolicyHead
/*
* The "type" is really part of the address as far as the routing
@@ -168,27 +150,53 @@ struct sockaddr_encap
#define SENT_IP4 0x0001 /* data is two struct in_addr */
#define SENT_IPSP 0x0002 /* data as in IP4/6 plus SPI */
#define SENT_IP6 0x0004
-#define SENT_IPSP6 0x0008
-/*
- * SENT_HDRLEN is the length of the "header"
- * SENT_*_LEN are the lengths of various forms of sen_data
- * SENT_*_OFF are the offsets in the sen_data array of various fields
- */
+#define SENT_LEN sizeof(struct sockaddr_encap)
-#define SENT_HDRLEN (2 * sizeof(u_int8_t) + sizeof(u_int16_t))
+struct ipsec_acquire
+{
+ union sockaddr_union ipa_addr;
+ u_int64_t ipa_expire;
+ TAILQ_ENTRY(ipsec_acquire) ipa_next;
+};
+
+struct ipsec_policy
+{
+ struct sockaddr_encap ipo_addr;
+ struct sockaddr_encap ipo_mask;
+
+ union sockaddr_union ipo_src; /* Local address to use */
+ union sockaddr_union ipo_dst; /* Remote gateway -- if it's zeroed:
+ * - on output, we try to contact the
+ * remote host directly (if needed).
+ * - on input, we accept on if the
+ * inner source is the same as the
+ * outer source address, or if transport
+ * mode was used.
+ */
+
+ u_int64_t ipo_last_searched; /* Timestamp of last lookup */
+
+ u_int8_t ipo_flags; /* See IPSP_POLICY_* definitions */
+ u_int8_t ipo_type; /* USE/ACQUIRE/... */
+ u_int8_t ipo_sproto;/* ESP, AH; if zero we use system dflts */
-#define SENT_IP4_SRCOFF (0)
-#define SENT_IP4_DSTOFF (sizeof (struct in_addr))
+ struct tdb *ipo_tdb; /* Cached entry */
-#define SENT_IP6_SRCOFF (0)
-#define SENT_IP6_DSTOFF (sizeof (struct in6_addr))
+ TAILQ_ENTRY(ipsec_policy) ipo_tdb_next; /* List of policies on TDB */
+ TAILQ_ENTRY(ipsec_policy) ipo_list; /* List of all policy entries */
+};
+
+#define IPSP_POLICY_NONE 0x0000 /* No flags set */
-#define SENT_IP4_LEN 20
-#define SENT_IPSP_LEN 20
-#define SENT_IP6_LEN 44
-#define SENT_IPSP6_LEN 32
+#define IPSP_IPSEC_USE 0 /* Use if existing, don't bother establishing */
+#define IPSP_IPSEC_ACQUIRE 1 /* Try to acquire in parallel but let packet */
+#define IPSP_IPSEC_REQUIRE 2 /* Require SA */
+#define IPSP_PERMIT 3 /* Permit traffic through */
+#define IPSP_DENY 4 /* Deny traffic */
+#define IPSP_IPSEC_DONTACQ 5 /* Require, but don't acquire */
+/* Notification types */
#define NOTIFY_SOFT_EXPIRE 0 /* Soft expiration of SA */
#define NOTIFY_HARD_EXPIRE 1 /* Hard expiration of SA */
#define NOTIFY_REQUEST_SA 2 /* Establish an SA */
@@ -208,24 +216,19 @@ struct route_enc {
struct sockaddr_encap re_dst;
};
-struct flow
-{
- struct flow *flow_next; /* Next in flow chain */
- struct flow *flow_prev; /* Previous in flow chain */
- struct tdb *flow_sa; /* Pointer to the SA */
- union sockaddr_union flow_src; /* Source address */
- union sockaddr_union flow_srcmask; /* Source netmask */
- union sockaddr_union flow_dst; /* Destination address */
- union sockaddr_union flow_dstmask; /* Destination netmask */
- u_int8_t flow_proto; /* Transport protocol, if applicable */
- u_int8_t foo[3]; /* Alignment */
-};
-
struct tdb /* tunnel descriptor block */
{
- struct tdb *tdb_hnext; /* Next in hash chain */
- struct tdb *tdb_onext; /* Next in output */
- struct tdb *tdb_inext; /* Previous in output */
+ /*
+ * Each TDB is on three hash tables: one keyed on dst/spi/sproto,
+ * one keyed on dst/sproto, and one keyed on src/sproto. The first
+ * is used for finding a specific TDB, the second for finding TDBs
+ * TDBs for outgoing policy matching, and the third for incoming
+ * policy matching. The following three fields maintain the hash
+ * queues in those three tables.
+ */
+ struct tdb *tdb_hnext; /* dst/spi/sproto table */
+ struct tdb *tdb_anext; /* dst/sproto table */
+ struct tdb *tdb_snext; /* src/sproto table */
struct xformsw *tdb_xform; /* Transformation to use */
struct enc_xform *tdb_encalgxform; /* Encryption algorithm xform */
@@ -301,13 +304,9 @@ struct tdb /* tunnel descriptor block */
u_int8_t tdb_iv[4]; /* Used for HALF-IV ESP */
caddr_t tdb_interface;
- struct flow *tdb_flow; /* Which outboind flows use this SA */
- struct flow *tdb_access; /* Ingress access control */
- struct tdb *tdb_bind_out; /* Outgoing SA to use */
- TAILQ_HEAD(tdb_bind_head, tdb) tdb_bind_in;
- TAILQ_ENTRY(tdb) tdb_bind_in_next; /* Refering Incoming SAs */
TAILQ_HEAD(tdb_inp_head, inpcb) tdb_inp;
+ TAILQ_HEAD(tdb_policy_head, ipsec_policy) tdb_policy_head;
};
struct tdb_ident {
@@ -396,7 +395,9 @@ extern int encdebug;
extern int ipsec_acl;
extern int ipsec_keep_invalid;
extern int ipsec_in_use;
+extern u_int64_t ipsec_last_added;
extern int ipsec_require_pfs;
+extern int ipsec_expire_acquire;
extern int ipsec_soft_allocations;
extern int ipsec_exp_allocations;
@@ -421,6 +422,8 @@ extern struct auth_hash auth_hash_hmac_ripemd_160_96;
extern TAILQ_HEAD(expclusterlist_head, tdb) expclusterlist;
extern TAILQ_HEAD(explist_head, tdb) explist;
+extern TAILQ_HEAD(ipsec_policy_head, ipsec_policy) ipsec_policy_head;
+extern TAILQ_HEAD(ipsec_acquire_head, ipsec_acquire) ipsec_acquire_head;
extern struct xformsw xformsw[], *xformswNXFORMSW;
@@ -446,7 +449,6 @@ extern struct xformsw xformsw[], *xformswNXFORMSW;
/* Misc. */
extern char *inet_ntoa4(struct in_addr);
-
extern char *ipsp_address(union sockaddr_union);
/* TDB management routines */
@@ -454,8 +456,12 @@ extern void tdb_add_inp(struct tdb *tdb, struct inpcb *inp);
extern u_int32_t reserve_spi(u_int32_t, u_int32_t, union sockaddr_union *,
union sockaddr_union *, u_int8_t, int *);
extern struct tdb *gettdb(u_int32_t, union sockaddr_union *, u_int8_t);
+extern struct tdb *gettdbbyaddr(union sockaddr_union *, u_int8_t,
+ struct mbuf *, int);
+extern struct tdb *gettdbbysrc(union sockaddr_union *, u_int8_t,
+ struct mbuf *, int);
extern void puttdb(struct tdb *);
-extern void tdb_delete(struct tdb *, int, int);
+extern void tdb_delete(struct tdb *, int);
extern int tdb_init(struct tdb *, u_int16_t, struct ipsecinit *);
extern void tdb_expiration(struct tdb *, int);
/* Flag values for the last argument of tdb_expiration(). */
@@ -464,18 +470,6 @@ extern void tdb_expiration(struct tdb *, int);
extern int tdb_walk(int (*)(struct tdb *, void *), void *);
extern void handle_expirations(void *);
-/* Flow management routines */
-extern struct flow *get_flow(void);
-extern void put_flow(struct flow *, struct tdb *, int);
-extern void delete_flow(struct flow *, struct tdb *, int);
-extern struct flow *find_flow(union sockaddr_union *, union sockaddr_union *,
- union sockaddr_union *, union sockaddr_union *,
- u_int8_t, struct tdb *, int);
-extern struct flow *find_global_flow(union sockaddr_union *,
- union sockaddr_union *,
- union sockaddr_union *,
- union sockaddr_union *, u_int8_t);
-
/* XF_IP4 */
extern int ipe4_attach(void);
extern int ipe4_init(struct tdb *, struct xformsw *, struct ipsecinit *);
@@ -549,7 +543,7 @@ extern int tcp_signature_tdb_output __P((struct mbuf *, struct tdb *,
struct mbuf **, int, int));
/* Padding */
-extern caddr_t m_pad(struct mbuf *, int, int);
+extern caddr_t m_pad(struct mbuf *, int);
/* Replay window */
extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t,
@@ -560,8 +554,17 @@ extern unsigned char ipseczeroes[];
/* Packet processing */
extern int ipsp_process_packet(struct mbuf *, struct tdb *, int, int);
extern int ipsp_process_done(struct mbuf *, struct tdb *);
-extern struct tdb *ipsp_spd_lookup(struct mbuf *, int, int, int *);
+extern struct tdb *ipsp_spd_lookup(struct mbuf *, int, int, int *, int,
+ struct tdb *, struct inpcb *);
extern int ipsec_common_input_cb(struct mbuf *, struct tdb *, int, int);
-extern int ipsp_acquire_sa(struct tdb *);
+extern int ipsp_acquire_sa(struct ipsec_policy *, union sockaddr_union *,
+ union sockaddr_union *);
+extern struct ipsec_policy *ipsec_add_policy(struct sockaddr_encap *,
+ struct sockaddr_encap *,
+ union sockaddr_union *, int, int);
+extern int ipsp_match_policy(struct tdb *, struct ipsec_policy *,
+ struct mbuf *, int);
+extern void ipsp_acquire_expirations(void *);
+extern int ipsec_delete_policy(struct ipsec_policy *);
#endif /* _KERNEL */
#endif /* _NETINET_IPSP_H_ */
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 93a75eabf13..d38374eb455 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.80 2000/09/18 22:06:37 provos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.81 2000/09/19 03:20:59 angelos Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -130,7 +130,6 @@ ip_output(m0, va_alist)
union sockaddr_union sdst;
u_int32_t sspi;
- u_int8_t sa_require = 0, sa_have = 0;
struct inpcb *inp;
struct tdb *tdb;
int s;
@@ -285,7 +284,8 @@ ip_output(m0, va_alist)
&ip->ip_dst, sizeof(ip->ip_dst)))
tdb = inp->inp_tdb;
else
- tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error);
+ tdb = ipsp_spd_lookup(m, AF_INET, hlen, &error,
+ IPSP_DIRECTION_OUT, NULL, inp);
if (tdb == NULL) {
splx(s);
@@ -317,40 +317,22 @@ ip_output(m0, va_alist)
sproto = tdb->tdb_sproto;
/*
- * If the socket has set the bypass flags and SA destination
- * matches the IP destination, skip IPsec. This allows
- * IKE packets to travel through IPsec tunnels.
+ * If the socket has set the bypass flags and SA
+ * destination matches the IP destination, skip
+ * IPsec. This allows IKE packets to travel through
+ * IPsec tunnels.
*/
- if (inp != NULL &&
- inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS &&
- inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS &&
- inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS &&
- sdst.sa.sa_family == AF_INET &&
- !bcmp(&sdst.sin.sin_addr.s_addr, &ip->ip_dst.s_addr,
- sizeof(ip->ip_dst.s_addr))) {
+ if ((inp != NULL) &&
+ (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS)
+ && (sdst.sa.sa_family == AF_INET) &&
+ (sdst.sin.sin_addr.s_addr == ip->ip_dst.s_addr)) {
splx(s);
- sproto = 0; /* mark as no-IPsec-needed */
+ sproto = 0; /* mark as no-IPsec-needed */
goto done_spd;
}
- /* What are the socket (or default) security requirements ? */
- if (inp == NULL)
- sa_require = get_sa_require(NULL);
- else
- sa_require = inp->inp_secrequire;
-
- /*
- * Now we check if this tdb has all the transforms which
- * are required by the socket or our default policy.
- */
- SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb);
- splx(s);
- if (sa_require & ~sa_have) {
- error = EHOSTUNREACH;
- m_freem(m);
- goto done;
- }
-
/* If it's not a multicast packet, try to fast-path */
if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
goto sendit;
@@ -570,7 +552,6 @@ sendit:
/* Massage the IP header for use by the IPsec code */
ip->ip_len = htons((u_short) ip->ip_len);
ip->ip_off = htons((u_short) ip->ip_off);
- ip->ip_sum = 0;
/*
* Clear these -- they'll be set in the recursive invocation
@@ -816,9 +797,6 @@ ip_ctloutput(op, so, level, optname, mp)
register int optval = 0;
#ifdef IPSEC
struct proc *p = curproc; /* XXX */
- struct tdb *tdb;
- struct tdb_ident *tdbip, tdbi;
- int s;
#endif
int error = 0;
@@ -916,26 +894,6 @@ ip_ctloutput(op, so, level, optname, mp)
}
}
break;
- case IPSEC_OUTSA:
-#ifndef IPSEC
- error = EINVAL;
-#else
- s = spltdb();
- if (m == 0 || m->m_len != sizeof(struct tdb_ident)) {
- error = EINVAL;
- } else {
- tdbip = mtod(m, struct tdb_ident *);
- tdb = gettdb(tdbip->spi, &tdbip->dst,
- tdbip->proto);
- if (tdb == NULL)
- error = ESRCH;
- else
- tdb_add_inp(tdb, inp);
- }
- splx(s);
-#endif /* IPSEC */
- break;
-
case IP_AUTH_LEVEL:
case IP_ESP_TRANS_LEVEL:
case IP_ESP_NETWORK_LEVEL:
@@ -1064,26 +1022,6 @@ ip_ctloutput(op, so, level, optname, mp)
*mtod(m, int *) = optval;
break;
- case IPSEC_OUTSA:
-#ifndef IPSEC
- error = EINVAL;
-#else
- s = spltdb();
- if (inp->inp_tdb == NULL) {
- error = ENOENT;
- } else {
- tdbi.spi = inp->inp_tdb->tdb_spi;
- tdbi.dst = inp->inp_tdb->tdb_dst;
- tdbi.proto = inp->inp_tdb->tdb_sproto;
- *mp = m = m_get(M_WAIT, MT_SOOPTS);
- m->m_len = sizeof(tdbi);
- bcopy((caddr_t)&tdbi, mtod(m, caddr_t),
- (unsigned)m->m_len);
- }
- splx(s);
-#endif /* IPSEC */
- break;
-
case IP_AUTH_LEVEL:
case IP_ESP_TRANS_LEVEL:
case IP_ESP_NETWORK_LEVEL:
diff --git a/sys/netinet/ip_spd.c b/sys/netinet/ip_spd.c
new file mode 100644
index 00000000000..c5500b15bb5
--- /dev/null
+++ b/sys/netinet/ip_spd.c
@@ -0,0 +1,791 @@
+/* $OpenBSD: ip_spd.c,v 1.1 2000/09/19 03:20:59 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#endif /* INET */
+
+#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/in6_var.h>
+#endif /* INET6 */
+
+#include <net/pfkeyv2.h>
+
+#include <netinet/ip_ipsp.h>
+
+#ifdef ENCDEBUG
+#define DPRINTF(x) if (encdebug) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
+/*
+ * Lookup at the SPD based on the headers contained on the mbuf. The second
+ * argument indicates what protocol family the header at the beginning of
+ * the mbuf is. hlen is the the offset of the transport protocol header
+ * in the mbuf.
+ *
+ * Return combinations (of return value and in *error):
+ * - NULL/0 -> no IPsec required on packet
+ * - NULL/-EINVAL -> silently drop the packet
+ * - NULL/errno -> drop packet and return error
+ * or a pointer to a TDB (and 0 in *error).
+ *
+ * In the case of incoming flows, only the first three combinations are
+ * returned.
+ */
+struct tdb *
+ipsp_spd_lookup(struct mbuf *m, int af, int hlen, int *error, int direction,
+ struct tdb *tdbp, struct inpcb *inp)
+{
+ struct route_enc re0, *re = &re0;
+ union sockaddr_union sdst, ssrc;
+ struct sockaddr_encap *ddst;
+ struct ipsec_policy *ipo;
+ int ignore = 0;
+
+ /*
+ * If there are no flows in place, there's no point
+ * continuing with the SPD lookup.
+ */
+ if (!ipsec_in_use)
+ {
+ *error = 0;
+ return NULL;
+ }
+
+ /* If an input packet is destined to a BYPASS socket, just accept it */
+ if ((inp != NULL) && (direction == IPSP_DIRECTION_IN) &&
+ (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS))
+ {
+ *error = 0;
+ return NULL;
+ }
+
+ bzero((caddr_t) re, sizeof(struct route_enc));
+ bzero((caddr_t) &sdst, sizeof(union sockaddr_union));
+ bzero((caddr_t) &ssrc, sizeof(union sockaddr_union));
+ ddst = (struct sockaddr_encap *) &re->re_dst;
+ ddst->sen_family = PF_KEY;
+ ddst->sen_len = SENT_LEN;
+
+ switch (af)
+ {
+#ifdef INET
+ case AF_INET:
+ ddst->sen_direction = direction;
+ ddst->sen_type = SENT_IP4;
+
+ m_copydata(m, offsetof(struct ip, ip_src),
+ sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_src));
+ m_copydata(m, offsetof(struct ip, ip_dst),
+ sizeof(struct in_addr), (caddr_t) &(ddst->sen_ip_dst));
+ m_copydata(m, offsetof(struct ip, ip_p), sizeof(u_int8_t),
+ (caddr_t) &(ddst->sen_proto));
+
+ sdst.sin.sin_family = ssrc.sin.sin_family = AF_INET;
+ sdst.sin.sin_len = ssrc.sin.sin_len = sizeof(struct sockaddr_in);
+ ssrc.sin.sin_addr = ddst->sen_ip_src;
+ sdst.sin.sin_addr = ddst->sen_ip_dst;
+
+ /* If TCP/UDP, extract the port numbers to use in the lookup */
+ switch (ddst->sen_proto)
+ {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ /*
+ * Luckily, the offset of the src/dst ports in both the UDP
+ * and TCP headers is the same (first two 16-bit values
+ * in the respective headers), so we can just copy them.
+ */
+ m_copydata(m, hlen, sizeof(u_int16_t),
+ (caddr_t) &(ddst->sen_sport));
+ m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
+ (caddr_t) &(ddst->sen_dport));
+ break;
+
+ default:
+ ddst->sen_sport = 0;
+ ddst->sen_dport = 0;
+ }
+
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ ddst->sen_type = SENT_IP6;
+ ddst->sen_ip6_direction = direction;
+
+ m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
+ sizeof(struct in6_addr),
+ (caddr_t) &(ddst->sen_ip6_src));
+ m_copydata(m, offsetof(struct ip6_hdr, ip6_dst),
+ sizeof(struct in6_addr),
+ (caddr_t) &(ddst->sen_ip6_dst));
+ m_copydata(m, offsetof(struct ip6_hdr, ip6_nxt), sizeof(u_int8_t),
+ (caddr_t) &(ddst->sen_ip6_proto));
+
+ sdst.sin6.sin6_family = ssrc.sin6.sin6_family = AF_INET6;
+ sdst.sin6.sin6_len = ssrc.sin6.sin6_family =
+ sizeof(struct sockaddr_in6);
+ ssrc.sin6.sin6_addr = ddst->sen_ip6_src;
+ sdst.sin6.sin6_addr = ddst->sen_ip6_dst;
+
+ /* If TCP/UDP, extract the port numbers to use in the lookup */
+ switch (ddst->sen_ip6_proto)
+ {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ /*
+ * Luckily, the offset of the src/dst ports in both the UDP
+ * and TCP headers is the same (first two 16-bit values
+ * in the respective headers), so we can just copy them.
+ */
+ m_copydata(m, hlen, sizeof(u_int16_t),
+ (caddr_t) &(ddst->sen_ip6_sport));
+ m_copydata(m, hlen + sizeof(u_int16_t), sizeof(u_int16_t),
+ (caddr_t) &(ddst->sen_ip6_dport));
+ break;
+
+ default:
+ ddst->sen_ip6_sport = 0;
+ ddst->sen_ip6_dport = 0;
+ }
+
+ break;
+#endif /* INET6 */
+
+ default:
+ *error = EAFNOSUPPORT;
+ return NULL;
+ }
+
+ /* Actual SPD lookup */
+ rtalloc((struct route *) re);
+ if (re->re_rt == NULL)
+ {
+ *error = 0;
+ return NULL; /* Nothing found -- means no IPsec needed */
+ }
+
+ /* Sanity check */
+ if ((re->re_rt->rt_gateway == NULL) ||
+ (((struct sockaddr_encap *) re->re_rt->rt_gateway)->sen_type !=
+ SENT_IPSP))
+ {
+ DPRINTF(("ipsp_spd_lookup(): no gw, or gw data not IPSP\n"));
+ RTFREE(re->re_rt);
+ *error = EHOSTUNREACH;
+ return NULL;
+ }
+
+ ipo = ((struct sockaddr_encap *) (re->re_rt->rt_gateway))->sen_ipsp;
+ RTFREE(re->re_rt);
+ if (ipo == NULL)
+ {
+ DPRINTF(("ipsp_spd_lookup(): no policy present\n"));
+ *error = EHOSTUNREACH;
+ return NULL;
+ }
+
+ switch (ipo->ipo_type)
+ {
+ case IPSP_PERMIT:
+ *error = 0;
+ return NULL;
+
+ case IPSP_DENY:
+ *error = EHOSTUNREACH;
+ return NULL;
+
+ case IPSP_IPSEC_USE:
+ case IPSP_IPSEC_ACQUIRE:
+ case IPSP_IPSEC_REQUIRE:
+ case IPSP_IPSEC_DONTACQ:
+ /* Nothing more needed here */
+ break;
+
+ default:
+ *error = EINVAL;
+ return NULL;
+ }
+
+ /*
+ * Check for non-specific destination in the policy. If a specific
+ * destination was specified, use that -- otherwise, use the relevant
+ * information from the packet.
+ */
+ switch (ipo->ipo_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ if (ipo->ipo_dst.sin.sin_addr.s_addr != INADDR_ANY)
+ {
+ if (direction == IPSP_DIRECTION_OUT)
+ bcopy(&ipo->ipo_dst, &sdst, sizeof(union sockaddr_union));
+ else
+ bcopy(&ipo->ipo_dst, &ssrc, sizeof(union sockaddr_union));
+ }
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr))
+ {
+ if (direction == IPSP_DIRECTION_OUT)
+ bcopy(&ipo->ipo_dst, &sdst, sizeof(union sockaddr_union));
+ else
+ bcopy(&ipo->ipo_dst, &ssrc, sizeof(union sockaddr_union));
+ }
+ break;
+#endif /* INET6 */
+ }
+
+ switch (ipo->ipo_src.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ if (ipo->ipo_src.sin.sin_addr.s_addr != INADDR_ANY)
+ {
+ if (direction == IPSP_DIRECTION_OUT)
+ bcopy(&ipo->ipo_src, &ssrc, sizeof(union sockaddr_union));
+ else
+ bcopy(&ipo->ipo_src, &sdst, sizeof(union sockaddr_union));
+ }
+ else
+ ignore = 1;
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ if (!IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_src.sin6.sin6_addr))
+ {
+ if (direction == IPSP_DIRECTION_OUT)
+ bcopy(&ipo->ipo_src, &ssrc, sizeof(union sockaddr_union));
+ else
+ bcopy(&ipo->ipo_src, &sdst, sizeof(union sockaddr_union));
+ }
+ else
+ ignore = 1;
+ break;
+#endif /* INET6 */
+ }
+
+ /* Do we have a cached entry ? If so, check if it's still valid. */
+ if ((ipo->ipo_tdb) && (ipo->ipo_tdb->tdb_flags & TDBF_INVALID))
+ {
+ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next);
+ ipo->ipo_tdb = NULL;
+ }
+
+ /* Outgoing packet SPD lookup */
+ if (direction == IPSP_DIRECTION_OUT)
+ {
+ /*
+ * If the packet is destined for the policy-specified gateway/endhost,
+ * and the socket has the BYPASS option set, skip IPsec processing.
+ */
+ if ((inp != NULL) &&
+ (inp->inp_seclevel[SL_ESP_TRANS] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_ESP_NETWORK] == IPSEC_LEVEL_BYPASS) &&
+ (inp->inp_seclevel[SL_AUTH] == IPSEC_LEVEL_BYPASS))
+ {
+ /* Direct match */
+ if (bcmp(&sdst, &ipo->ipo_dst, sizeof(union sockaddr_union)) == 0)
+ {
+ *error = 0;
+ return NULL;
+ }
+
+ /* Same-host */
+ switch (ipo->ipo_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ if (ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_ANY)
+ {
+ *error = 0;
+ return NULL;
+ }
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr))
+ {
+ *error = 0;
+ return NULL;
+ }
+ break;
+#endif /* INET6 */
+ }
+ }
+
+ /* Check that the cached TDB (if present), is appropriate */
+ if (ipo->ipo_tdb)
+ {
+ if (bcmp(&sdst, &ipo->ipo_tdb->tdb_dst,
+ sizeof(union sockaddr_union)))
+ {
+ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo,
+ ipo_tdb_next);
+ ipo->ipo_tdb = NULL;
+
+ /* Fall through to acquisition of TDB */
+ }
+ else
+ return ipo->ipo_tdb; /* Cached entry is good, we're done */
+ }
+
+ /*
+ * If no SA has been added since the last time we did a lookup,
+ * there's no point searching for one.
+ */
+ if (ipo->ipo_last_searched <= ipsec_last_added)
+ {
+ ipo->ipo_last_searched = time.tv_sec; /* "touch" the entry */
+
+ /* Find an appropriate SA from among the existing SAs */
+ ipo->ipo_tdb = gettdbbyaddr(&sdst, ipo->ipo_sproto, m, af);
+ if (ipo->ipo_tdb)
+ {
+ TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo,
+ ipo_tdb_next);
+ *error = 0;
+ ipo->ipo_last_searched = 0;
+ return ipo->ipo_tdb;
+ }
+ }
+
+ /* So, we don't have an SA -- just a policy */
+ switch (ipo->ipo_type)
+ {
+ case IPSP_IPSEC_REQUIRE:
+ /* Acquire SA through key management */
+ if (ipsp_acquire_sa(ipo, &sdst, ignore ? NULL : &ssrc) != 0)
+ {
+ *error = EACCES;
+ return NULL;
+ }
+
+ /* Fall through */
+
+ case IPSP_IPSEC_DONTACQ:
+ *error = -EINVAL; /* Silently drop packet */
+ return NULL;
+
+ case IPSP_IPSEC_ACQUIRE:
+ /* Acquire SA through key management */
+ if (ipsp_acquire_sa(ipo, &sdst, ignore ? NULL : &ssrc) != 0)
+ {
+ *error = EACCES;
+ return NULL;
+ }
+
+ /* Fall through */
+
+ case IPSP_IPSEC_USE:
+ *error = 0; /* Let packet through */
+ return NULL;
+ }
+ }
+ else /* IPSP_DIRECTION_IN */
+ {
+ /* Check the cached entry */
+ if ((ipo->ipo_tdb) &&
+ bcmp(&ssrc, &ipo->ipo_tdb->tdb_src, sizeof(union sockaddr_union)))
+ {
+ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next);
+ ipo->ipo_tdb = NULL;
+ }
+
+ switch (ipo->ipo_type)
+ {
+ case IPSP_IPSEC_DONTACQ:
+ /* Does protection match stated policy ? */
+ if (tdbp && ipsp_match_policy(tdbp, ipo, m, af))
+ {
+ /* Accept packet */
+ *error = 0;
+ return NULL;
+ }
+
+ /* Silently drop packet */
+ *error = EHOSTUNREACH;
+ return NULL;
+
+ case IPSP_IPSEC_REQUIRE:
+ if (tdbp && ipsp_match_policy(tdbp, ipo, m, af))
+ {
+ /* Accept packet */
+ *error = 0;
+ return NULL;
+ }
+
+ /* If we have a cached entry, just discard the packet */
+ if (ipo->ipo_tdb)
+ {
+ *error = EHOSTUNREACH;
+ return NULL;
+ }
+
+ /*
+ * Find whether there exists an appropriate SA. If so, drop
+ * the packet. Otherwise, try to acquire one (from below).
+ *
+ * If no SA has been added since the last time we did a lookup,
+ * there's no point searching for one.
+ */
+ if (ipo->ipo_last_searched <= ipsec_last_added)
+ {
+ ipo->ipo_last_searched = time.tv_sec; /* "touch" */
+
+ if ((ipo->ipo_tdb = gettdbbysrc(&ssrc, ipo->ipo_sproto,
+ m, af)) != NULL)
+ {
+ TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo,
+ ipo_tdb_next);
+ ipo->ipo_last_searched = 0;
+ *error = EHOSTUNREACH;
+ return NULL;
+ }
+ }
+
+ /* Acquire SA through key management */
+ if ((*error = ipsp_acquire_sa(ipo, &ssrc,
+ ignore ? NULL : &sdst)) != 0)
+ return NULL;
+
+ *error = -EINVAL;
+ return NULL;
+
+ case IPSP_IPSEC_USE:
+ /*
+ * It doesn't matter what protection it had (if any),
+ * just accept it -- equivalent to PERMIT for input.
+ * This means we can't say that we want in incoming
+ * packet to be unprotected -- at least not directly;
+ * we can always have a DENY policy for ESP/AH packets.
+ */
+ *error = 0;
+ return NULL;
+
+ case IPSP_IPSEC_ACQUIRE:
+ /*
+ * We don't check for policy match, since we would
+ * accept clear-text packets as well.
+ */
+
+ /* If we have a cached entry, just accept the packet */
+ if (ipo->ipo_tdb)
+ {
+ *error = 0;
+ return NULL;
+ }
+
+ /*
+ * Find whether there exists an appropriate SA. If so, accept
+ * the packet. Otherwise, try to acquire one (from below).
+ *
+ * If no SA has been added since the last time we did a lookup,
+ * there's no point searching for one.
+ */
+ if (ipo->ipo_last_searched <= ipsec_last_added)
+ {
+ ipo->ipo_last_searched = time.tv_sec; /* "touch" */
+
+ if ((ipo->ipo_tdb = gettdbbysrc(&ssrc, ipo->ipo_sproto,
+ m, af)) != NULL)
+ {
+ TAILQ_INSERT_TAIL(&ipo->ipo_tdb->tdb_policy_head, ipo,
+ ipo_tdb_next);
+ ipo->ipo_last_searched = 0;
+ *error = 0;
+ return NULL;
+ }
+ }
+
+ /* Acquire SA through key management */
+ if ((*error = ipsp_acquire_sa(ipo, &ssrc,
+ ignore ? NULL : &sdst)) != 0)
+ return NULL;
+
+ /* Just accept the packet */
+ *error = 0;
+ return NULL;
+ }
+ }
+
+ /* Shouldn't ever get this far */
+ *error = EINVAL;
+ return NULL;
+}
+
+
+/*
+ * See if a specific SA satisfies stated policy. Return 0 if false, 1 (or
+ * non-zero) otherwise.
+ */
+int
+ipsp_match_policy(struct tdb *tdb, struct ipsec_policy *ipo,
+ struct mbuf *m, int af)
+{
+ union sockaddr_union peer;
+ int pflag = 0;
+
+ switch (ipo->ipo_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ if (ipo->ipo_dst.sin.sin_addr.s_addr == INADDR_ANY)
+ pflag = 1;
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&ipo->ipo_dst.sin6.sin6_addr))
+ pflag = 1;
+ break;
+#endif /* INET6 */
+
+ case 0: /* Just in case */
+ pflag = 1;
+ break;
+
+ default:
+ return 0; /* Unknown/unsupported network protocol */
+ }
+
+ if (pflag == 0)
+ bcopy(&ipo->ipo_dst, &peer, sizeof(union sockaddr_union));
+ else
+ {
+ bzero(&peer, sizeof(union sockaddr_union));
+
+ /* Need to copy the source address from the packet */
+ switch (af)
+ {
+#ifdef INET
+ case AF_INET:
+ peer.sin.sin_family = AF_INET;
+ peer.sin.sin_len = sizeof(struct sockaddr_in);
+ m_copydata(m, offsetof(struct ip, ip_src),
+ sizeof(struct in_addr),
+ (caddr_t) &peer.sin.sin_addr);
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ peer.sin6.sin6_family = AF_INET6;
+ peer.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
+ sizeof(struct in6_addr),
+ (caddr_t) &peer.sin6.sin6_addr);
+ break;
+#endif /* INET6 */
+
+ default:
+ return 0; /* Unknown/unsupported network protocol */
+ }
+ }
+
+ /*
+ * Does the packet use the right security protocol and is coming from
+ * the right peer ?
+ */
+ if ((tdb->tdb_sproto == ipo->ipo_sproto) &&
+ (!bcmp(&tdb->tdb_src, &peer, sizeof(union sockaddr_union))))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Delete a policy from the SPD.
+ */
+int
+ipsec_delete_policy(struct ipsec_policy *ipo)
+{
+ int err;
+
+ /* Delete */
+ err = rtrequest(RTM_DELETE, (struct sockaddr *) &ipo->ipo_addr,
+ (struct sockaddr *) 0, (struct sockaddr *) &ipo->ipo_mask,
+ 0, (struct rtentry **) 0);
+
+ if (ipo->ipo_tdb)
+ TAILQ_REMOVE(&ipo->ipo_tdb->tdb_policy_head, ipo, ipo_tdb_next);
+
+ TAILQ_REMOVE(&ipsec_policy_head, ipo, ipo_list);
+ FREE(ipo, M_TDB);
+ ipsec_in_use--;
+
+ return err;
+}
+
+/*
+ * Add a policy to the SPD.
+ */
+struct ipsec_policy *
+ipsec_add_policy(struct sockaddr_encap *dst, struct sockaddr_encap *mask,
+ union sockaddr_union *sdst, int type, int sproto)
+{
+ struct sockaddr_encap encapgw;
+ struct ipsec_policy *ipon;
+
+ MALLOC(ipon, struct ipsec_policy *, sizeof(struct ipsec_policy), M_TDB,
+ M_NOWAIT);
+ if (ipon == NULL)
+ return NULL;
+
+ bzero(ipon, sizeof(struct ipsec_policy));
+ bzero((caddr_t) &encapgw, sizeof(struct sockaddr_encap));
+
+ encapgw.sen_len = SENT_LEN;
+ encapgw.sen_family = PF_KEY;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp = ipon;
+
+ if (rtrequest(RTM_ADD, (struct sockaddr *) dst,
+ (struct sockaddr *) &encapgw, (struct sockaddr *) mask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0) != 0)
+ {
+ DPRINTF(("ipsec_add_policy: failed to add policy\n"));
+ FREE(ipon, M_TDB);
+ return NULL;
+ }
+
+ ipsec_in_use++;
+
+ bcopy(dst, &ipon->ipo_addr, sizeof(struct sockaddr_encap));
+ bcopy(mask, &ipon->ipo_mask, sizeof(struct sockaddr_encap));
+ bcopy(sdst, &ipon->ipo_dst, sizeof(union sockaddr_union));
+ ipon->ipo_sproto = sproto;
+ ipon->ipo_type = type;
+
+ TAILQ_INSERT_HEAD(&ipsec_policy_head, ipon, ipo_list);
+
+ return ipon;
+}
+
+/*
+ * Expire old acquire requests to key management.
+ */
+void
+ipsp_acquire_expirations(void *arg)
+{
+ struct ipsec_acquire *ipa;
+
+ for (ipa = TAILQ_FIRST(&ipsec_acquire_head);
+ ipa;
+ ipa = TAILQ_FIRST(&ipsec_acquire_head))
+ {
+ if (ipa->ipa_expire <= time.tv_sec)
+ {
+ /* Remove from the list and free */
+ TAILQ_REMOVE(&ipsec_acquire_head, ipa, ipa_next);
+ FREE(ipa, M_TDB);
+ }
+ else
+ {
+ /* Schedule us for another expiration */
+ timeout(ipsp_acquire_expirations, (void *) NULL,
+ hz * (ipa->ipa_expire - time.tv_sec));
+ return;
+ }
+ }
+
+ /* If there's no request pending, we don't need to schedule us */
+
+ return;
+}
+
+/*
+ * Signal key management that we need an SA.
+ */
+int
+ipsp_acquire_sa(struct ipsec_policy *ipo, union sockaddr_union *gw,
+ union sockaddr_union *laddr)
+{
+ struct ipsec_acquire *ipa;
+
+ /*
+ * Check whether request has been made already.
+ * XXX We need a more scalable data structure instead of a list.
+ */
+ for (ipa = TAILQ_FIRST(&ipsec_acquire_head);
+ ipa;
+ ipa = TAILQ_NEXT(ipa, ipa_next))
+ {
+ /* Already in process */
+ if (!bcmp(gw, &ipa->ipa_addr, sizeof(union sockaddr_union)))
+ return 0;
+ }
+
+ /* Add request in cache and proceed */
+ MALLOC(ipa, struct ipsec_acquire *, sizeof(struct ipsec_acquire),
+ M_TDB, M_DONTWAIT);
+ if (ipa == NULL)
+ return ENOMEM;
+ bcopy(gw, &ipa->ipa_addr, sizeof(union sockaddr_union));
+ ipa->ipa_expire = time.tv_sec + ipsec_expire_acquire;
+ TAILQ_INSERT_TAIL(&ipsec_acquire_head, ipa, ipa_next);
+
+ if (TAILQ_FIRST(&ipsec_acquire_head) == ipa)
+ timeout(ipsp_acquire_expirations, (void *) NULL,
+ hz * (ipa->ipa_expire - time.tv_sec));
+
+ /* PF_KEYv2 notification message */
+ return pfkeyv2_acquire(ipo, gw, laddr);
+}
diff --git a/sys/netinet/ipsec_input.c b/sys/netinet/ipsec_input.c
index bcd4b5d9e85..de37437259d 100644
--- a/sys/netinet/ipsec_input.c
+++ b/sys/netinet/ipsec_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipsec_input.c,v 1.31 2000/09/17 19:52:24 angelos Exp $ */
+/* $OpenBSD: ipsec_input.c,v 1.32 2000/09/19 03:20:59 angelos Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
@@ -77,6 +77,8 @@
#include "bpfilter.h"
+#define PI_MAGIC 0xdeadbeef /* XXX horror! */
+
int ipsec_common_input(struct mbuf *, int, int, int, int);
#ifdef ENCDEBUG
@@ -214,7 +216,7 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
{
/*
* XXX The fragment conflicts with scoped nature of IPv6, so do it for
- * only for IPv4 for now
+ * only for IPv4 for now.
*/
if (tdbp->tdb_interface)
m->m_pkthdr.rcvif = (struct ifnet *) tdbp->tdb_interface;
@@ -229,16 +231,6 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
tdb_expiration(tdbp, TDBEXP_TIMEOUT);
}
- /* If we do ingress filtering and the list is empty, quick drop */
- if (ipsec_acl && (tdbp->tdb_access == NULL))
- {
- DPRINTF(("ipsec_common_input(): packet dropped due to empty policy list, SA %s/%08x/%u\n", ipsp_address(tdbp->tdb_dst), ntohl(spi), tdbp->tdb_sproto));
- splx(s);
- m_freem(m);
- IPSEC_ISTAT(espstat.esps_pdrops, ahstat.ahs_pdrops);
- return EACCES;
- }
-
/*
* Call appropriate transform and return -- callback takes care of
* everything else.
@@ -262,10 +254,8 @@ ipsec_common_input(struct mbuf *m, int skip, int protoff, int af, int sproto)
int
ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff)
{
- union sockaddr_union src_address, dst_address, src2, dst2;
- caddr_t sport = 0, dport = 0;
int prot, af, sproto;
- struct flow *flow;
+
#if NBPFILTER > 0
struct ifnet *bpfif;
#endif
@@ -289,8 +279,6 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff)
return EINVAL;
}
- bcopy(&tdbp->tdb_dst, &dst_address, tdbp->tdb_dst.sa.sa_len);
-
#ifdef INET
/* Fix IPv4 header */
if (tdbp->tdb_dst.sa.sa_family == AF_INET)
@@ -455,7 +443,7 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff)
((tdbp->tdb_src.sa.sa_family != AF_INET6) &&
(tdbp->tdb_src.sa.sa_family != 0)))
{
- DPRINTF(("ipsec_common_input_cb(): packet %s to %s does not match any ACL entries, SA %s/%08x\n", ipsp_address(src_address), ipsp_address(dst_address), ipsp_address(tdbp->tdb_src), ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi)));
+ DPRINTF(("ipsec_common_input_cb(): packet %s to %s does not match any ACL entries, SA %s/%08x\n", ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst), ipsp_address(tdbp->tdb_src), ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi)));
m_freem(m);
IPSEC_ISTAT(espstat.esps_pdrops, ahstat.ahs_pdrops);
return EACCES;
@@ -463,112 +451,26 @@ ipsec_common_input_cb(struct mbuf *m, struct tdb *tdbp, int skip, int protoff)
}
#endif /* INET6 */
- /* Access control */
- if (ipsec_acl)
- {
- bzero(&src_address, sizeof(src_address));
- src_address.sa.sa_family = af;
- src_address.sa.sa_len = dst_address.sa.sa_len;
-
-#ifdef INET
- if (af == AF_INET)
- {
- m_copydata(m, offsetof(struct ip, ip_src), sizeof(struct in_addr),
- (caddr_t) &(src_address.sin.sin_addr));
- sport = (caddr_t) &src_address.sin.sin_port;
- dport = (caddr_t) &dst_address.sin.sin_port;
- }
-#endif /* INET */
-
-#ifdef INET6
- if (af == AF_INET6)
- {
- m_copydata(m, offsetof(struct ip6_hdr, ip6_src),
- sizeof(struct in6_addr),
- (caddr_t) &(src_address.sin6.sin6_addr));
- sport = (caddr_t) &src_address.sin6.sin6_port;
- dport = (caddr_t) &dst_address.sin6.sin6_port;
- }
-#endif /* INET6 */
-
- /* Save transport layer source/destination ports, if any */
- switch (prot)
- {
- case IPPROTO_TCP:
- m_copydata(m, skip + offsetof(struct tcphdr, th_sport),
- sizeof(u_int16_t), (caddr_t) sport);
- m_copydata(m, skip + offsetof(struct tcphdr, th_dport),
- sizeof(u_int16_t), (caddr_t) dport);
- break;
-
- case IPPROTO_UDP:
- m_copydata(m, skip + offsetof(struct udphdr, uh_sport),
- sizeof(u_int16_t), (caddr_t) sport);
- m_copydata(m, skip + offsetof(struct udphdr, uh_dport),
- sizeof(u_int16_t), (caddr_t) dport);
- break;
-
- default:
- /* Nothing needed */
- }
-
- for (flow = tdbp->tdb_access; flow; flow = flow->flow_next)
- {
- /* Match for address family */
- if (flow->flow_src.sa.sa_family != af)
- continue;
-
- /* Match for transport protocol */
- if (flow->flow_proto && flow->flow_proto != prot)
- continue;
-
- /* Netmask handling */
- rt_maskedcopy(&src_address.sa, &src2.sa, &flow->flow_srcmask.sa);
- rt_maskedcopy(&dst_address.sa, &dst2.sa, &flow->flow_dstmask.sa);
-
- /* Check addresses */
- if (bcmp(&src2, &flow->flow_src, src2.sa.sa_len) ||
- bcmp(&dst2, &flow->flow_dst, dst2.sa.sa_len))
- continue;
-
- break; /* success! */
- }
-
- if (flow == NULL)
- {
- /* Failed to match any entry in the ACL */
- DPRINTF(("ipsec_common_input_cb(): packet from %s to %s dropped due to policy, SA %s/%08x\n", ipsp_address(src_address), ipsp_address(dst_address), ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi)));
- m_freem(m);
- IPSEC_ISTAT(espstat.esps_pdrops, ahstat.ahs_pdrops);
- return EACCES;
- }
- }
+ /*
+ * Record what we've done to the packet (under what SA it was
+ * processed).
+ */
+ if (m->m_pkthdr.tdbi && m->m_pkthdr.tdbi != (void *) PI_MAGIC)
+ free(m->m_pkthdr.tdbi, M_TEMP);
- if (prot == IPPROTO_TCP || prot == IPPROTO_UDP)
+ MALLOC(m->m_pkthdr.tdbi, void *, sizeof(struct tdb_ident), M_TEMP,
+ M_NOWAIT);
+ if (m->m_pkthdr.tdbi == NULL)
{
- if (tdbp->tdb_bind_out)
- {
- if (!(m->m_flags & M_PKTHDR))
- DPRINTF(("ipsec_common_input_cb(): mbuf is not a packet header!\n"));
-
- MALLOC(m->m_pkthdr.tdbi, struct tdb_ident *,
- sizeof(struct tdb_ident), M_TEMP, M_NOWAIT);
-
- if (m->m_pkthdr.tdbi == NULL)
- {
- ((struct tdb_ident *) m->m_pkthdr.tdbi)->spi =
- tdbp->tdb_bind_out->tdb_spi;
- ((struct tdb_ident *) m->m_pkthdr.tdbi)->dst =
- tdbp->tdb_bind_out->tdb_dst;
- ((struct tdb_ident *) m->m_pkthdr.tdbi)->proto =
- tdbp->tdb_bind_out->tdb_sproto;
- }
- }
- else
- m->m_pkthdr.tdbi = NULL;
+ m_freem(m);
+ IPSEC_ISTAT(espstat.esps_hdrops, ahstat.ahs_hdrops);
+ return ENOMEM;
}
- else
- m->m_pkthdr.tdbi = NULL;
+
+ bcopy(&tdbp->tdb_dst, &(((struct tdb_ident *) m->m_pkthdr.tdbi)->dst),
+ sizeof(union sockaddr_union));
+ ((struct tdb_ident *) m->m_pkthdr.tdbi)->proto = tdbp->tdb_sproto;
+ ((struct tdb_ident *) m->m_pkthdr.tdbi)->spi = tdbp->tdb_spi;
if (sproto == IPPROTO_ESP)
{
@@ -726,7 +628,7 @@ ah4_input_cb(struct mbuf *m, ...)
if (IF_QFULL(ifq))
{
IF_DROP(ifq);
- if (m->m_pkthdr.tdbi)
+ if (m->m_pkthdr.tdbi && m->m_pkthdr.tdbi != (void *) PI_MAGIC)
free(m->m_pkthdr.tdbi, M_TEMP);
m_freem(m);
ahstat.ahs_qfull++;
@@ -768,7 +670,7 @@ esp4_input_cb(struct mbuf *m, ...)
if (IF_QFULL(ifq))
{
IF_DROP(ifq);
- if (m->m_pkthdr.tdbi)
+ if (m->m_pkthdr.tdbi && m->m_pkthdr.tdbi != (void *) PI_MAGIC)
free(m->m_pkthdr.tdbi, M_TEMP);
m_freem(m);
espstat.esps_qfull++;
@@ -875,8 +777,10 @@ ah6_input_cb(struct mbuf *m, int off, int protoff)
return 0;
bad:
+ if (m->m_pkthdr.tdbi && m->m_pkthdr.tdbi != (void *) PI_MAGIC)
+ free(m->m_pkthdr.tdbi, M_TEMP);
m_freem(m);
- return EINVAL; /*?*/
+ return EINVAL;
}
/* IPv6 ESP wrapper */
diff --git a/sys/netinet/ipsec_output.c b/sys/netinet/ipsec_output.c
new file mode 100644
index 00000000000..26bccf8fa6a
--- /dev/null
+++ b/sys/netinet/ipsec_output.c
@@ -0,0 +1,361 @@
+/* $OpenBSD: ipsec_output.c,v 1.1 2000/09/19 03:20:59 angelos Exp $ */
+
+/*
+ * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
+ *
+ * Copyright (c) 2000 Angelos D. Keromytis.
+ *
+ * Permission to use, copy, and modify this software without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#endif /* INET */
+
+#ifdef INET6
+#ifndef INET
+#include <netinet/in.h>
+#endif
+#include <netinet6/in6_var.h>
+#endif /* INET6 */
+
+#include <netinet/ip_ipsp.h>
+#include <netinet/ip_ah.h>
+#include <netinet/ip_esp.h>
+
+#ifdef ENCDEBUG
+#define DPRINTF(x) if (encdebug) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
+/*
+ * Loop over a tdb chain, taking into consideration protocol tunneling. The
+ * fourth argument is set if the first encapsulation header is already in
+ * place.
+ */
+int
+ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
+{
+ int i, off, error;
+ struct mbuf *mp;
+
+#ifdef INET
+ struct ip *ip;
+#endif /* INET */
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif /* INET6 */
+
+ /* Check that the transform is allowed by the administrator */
+ if ((tdb->tdb_sproto == IPPROTO_ESP && !esp_enable) ||
+ (tdb->tdb_sproto == IPPROTO_AH && !ah_enable))
+ {
+ DPRINTF(("ipsp_process_packet(): IPSec outbound packet dropped due to policy (check your sysctls)\n"));
+ m_freem(m);
+ return EHOSTUNREACH;
+ }
+
+ /* Sanity check */
+ if (!tdb->tdb_xform)
+ {
+ DPRINTF(("ipsp_process_packet(): uninitialized TDB\n"));
+ m_freem(m);
+ return EHOSTUNREACH;
+ }
+
+ /* Check if the SPI is invalid */
+ if (tdb->tdb_flags & TDBF_INVALID)
+ {
+ DPRINTF(("ipsp_process_packet(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto));
+ m_freem(m);
+ return ENXIO;
+ }
+
+ /* Check that the network protocol is supported */
+ switch (tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif /* INET6 */
+
+ default:
+ DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family));
+ m_freem(m);
+ return ENXIO;
+ }
+
+ /* Register first use if applicable, setup relevant expiration timer */
+ if (tdb->tdb_first_use == 0)
+ {
+ tdb->tdb_first_use = time.tv_sec;
+ tdb_expiration(tdb, TDBEXP_TIMEOUT);
+ }
+
+ /*
+ * Check for tunneling if we don't have the first header in place.
+ * When doing Ethernet-over-IP, we are handed an already-encapsulated
+ * frame, so we don't need to re-encapsulate.
+ */
+ if (tunalready == 0)
+ {
+ /*
+ * If the target protocol family is different, we know we'll be
+ * doing tunneling.
+ */
+ if (af == tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ if (af == AF_INET)
+ i = sizeof(struct ip);
+#endif /* INET */
+
+#ifdef INET6
+ if (af == AF_INET6)
+ i = sizeof(struct ip6_hdr);
+#endif /* INET6 */
+
+ /* Bring the network header in the first mbuf */
+ if (m->m_len < i)
+ {
+ if ((m = m_pullup(m, i)) == 0)
+ return ENOBUFS;
+ }
+
+#ifdef INET
+ ip = mtod(m, struct ip *);
+#endif /* INET */
+
+#ifdef INET6
+ ip6 = mtod(m, struct ip6_hdr *);
+#endif /* INET6 */
+ }
+
+ /* Do the appropriate encapsulation, if necessary */
+ if ((tdb->tdb_dst.sa.sa_family != af) || /* PF mismatch */
+ (tdb->tdb_flags & TDBF_TUNNELING) || /* Tunneling requested */
+ (tdb->tdb_xform->xf_type == XF_IP4) || /* ditto */
+#ifdef INET
+ ((tdb->tdb_dst.sa.sa_family == AF_INET) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) &&
+ (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) ||
+#endif /* INET */
+#ifdef INET6
+ ((tdb->tdb_dst.sa.sa_family == AF_INET6) &&
+ (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) &&
+ (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr,
+ &ip6->ip6_dst))) ||
+#endif /* INET6 */
+ 0)
+ {
+#ifdef INET
+ /* Fix IPv4 header checksum and length */
+ if (af == AF_INET)
+ {
+ if ((m = m_pullup(m, sizeof(struct ip))) == 0)
+ return ENOBUFS;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
+ }
+#endif /* INET */
+
+#ifdef INET6
+ /* Fix IPv6 header payload length */
+ if (af == AF_INET6)
+ {
+ if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0)
+ return ENOBUFS;
+
+ if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
+ /* no jumbogram support */
+ m_freem(m);
+ return ENXIO; /*?*/
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
+ }
+#endif /* INET6 */
+
+ /* Encapsulate -- the last two arguments are unused */
+ error = ipip_output(m, tdb, &mp, 0, 0);
+ if ((mp == NULL) && (!error))
+ error = EFAULT;
+ if (error)
+ {
+ if (mp)
+ {
+ m_freem(mp);
+ mp = NULL;
+ }
+
+ return error;
+ }
+
+ m = mp;
+ mp = NULL;
+ }
+
+ /* We may be done with this TDB */
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ return ipsp_process_done(m, tdb);
+ }
+ else
+ {
+ /*
+ * If this is just an IP-IP TDB and we're told there's already an
+ * encapsulation header, move on.
+ */
+ if (tdb->tdb_xform->xf_type == XF_IP4)
+ return ipsp_process_done(m, tdb);
+ }
+
+ /* Extract some information off the headers */
+ switch (tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ ip = mtod(m, struct ip *);
+ i = ip->ip_hl << 2;
+ off = offsetof(struct ip, ip_p);
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ ip6 = mtod(m, struct ip6_hdr *);
+ i = sizeof(struct ip6_hdr);
+ off = offsetof(struct ip6_hdr, ip6_nxt);
+ break;
+#endif /* INET6 */
+ }
+
+ /* Invoke the IPsec transform */
+ return (*(tdb->tdb_xform->xf_output))(m, tdb, NULL, i, off);
+}
+
+/*
+ * Called by the IPsec output transform callbacks, to transmit the packet
+ * or do further processing, as necessary.
+ */
+int
+ipsp_process_done(struct mbuf *m, struct tdb *tdb)
+{
+#ifdef INET
+ struct ip *ip;
+#endif /* INET */
+
+#ifdef INET6
+ struct ip6_hdr *ip6;
+#endif /* INET6 */
+
+ switch (tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ /* Fix the header length, for AH processing */
+ if (tdb->tdb_dst.sa.sa_family == AF_INET)
+ {
+ ip = mtod(m, struct ip *);
+ ip->ip_len = htons(m->m_pkthdr.len);
+ }
+ break;
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ /* Fix the header length, for AH processing */
+ if (tdb->tdb_dst.sa.sa_family == AF_INET6)
+ {
+ if (m->m_pkthdr.len < sizeof(*ip6)) {
+ m_freem(m);
+ return ENXIO;
+ }
+ if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
+ /* no jumbogram support */
+ m_freem(m);
+ return ENXIO; /*?*/
+ }
+
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
+ }
+ break;
+#endif /* INET6 */
+
+ default:
+ m_freem(m);
+ DPRINTF(("ipsp_process_done(): unknown protocol family (%d)\n",
+ tdb->tdb_dst.sa.sa_family));
+ return ENXIO;
+ }
+
+ /*
+ * We're done with IPsec processing, transmit the packet using the
+ * appropriate network protocol (IP or IPv6). SPD lookup will be
+ * performed again there.
+ */
+ switch (tdb->tdb_dst.sa.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+
+ return ip_output(m, NULL, NULL, IP_ENCAPSULATED | IP_RAWOUTPUT,
+ NULL, NULL);
+#endif /* INET */
+
+#ifdef INET6
+ case AF_INET6:
+ /*
+ * We don't need massage, IPv6 header fields are always in
+ * net endian
+ */
+ return ip6_output(m, NULL, NULL, IPV6_ENCAPSULATED, NULL, NULL);
+#endif /* INET6 */
+ }
+
+ /* Not reached */
+ return EINVAL;
+}
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 6dc96735557..19d15bfac28 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: raw_ip.c,v 1.20 1999/12/19 02:54:29 itojun Exp $ */
+/* $OpenBSD: raw_ip.c,v 1.21 2000/09/19 03:20:59 angelos Exp $ */
/* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */
/*
@@ -69,10 +69,6 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet/in_var.h>
#include <netinet/ip_icmp.h>
-#ifdef IPSEC
-extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
-#endif
-
#include <machine/stdarg.h>
struct inpcbtable rawcbtable;
@@ -448,7 +444,7 @@ rip_usrreq(so, req, m, nam, control)
dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr;
}
#ifdef IPSEC
- if (!(error = check_ipsec_policy(inp, dst)))
+ /* XXX Find an IPsec TDB */
#endif
error = rip_output(m, so, dst);
m = NULL;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index d21db5f3f32..45e28e9a560 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_input.c,v 1.71 2000/09/18 23:59:39 fgsch Exp $ */
+/* $OpenBSD: tcp_input.c,v 1.72 2000/09/19 03:20:59 angelos Exp $ */
/* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */
/*
@@ -90,6 +90,8 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet/icmp6.h>
#include <netinet6/nd6.h>
+#define PI_MAGIC 0xdeadbeef /* XXX the horror! */
+
struct tcpiphdr tcp_saveti;
struct tcpipv6hdr tcp_saveti6;
@@ -384,32 +386,29 @@ tcp_input(m, va_alist)
int iphlen;
va_list ap;
register struct tcphdr *th;
-#ifdef IPSEC
- struct tdb *tdb = NULL;
-#endif /* IPSEC */
#ifdef INET6
struct in6_addr laddr6;
struct ip6_hdr *ipv6 = NULL;
#endif /* INET6 */
+#ifdef IPSEC
+ struct tdb_ident *tdbi;
+ struct tdb *tdb;
+ int error, s;
+#endif /* IPSEC */
int af;
+#ifdef IPSEC
+ tdbi = (struct tdb_ident *) m->m_pkthdr.tdbi;
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
+#endif /* IPSEC */
+
va_start(ap, m);
iphlen = va_arg(ap, int);
va_end(ap);
tcpstat.tcps_rcvtotal++;
-#ifdef IPSEC
- /* Save the last SA which was used to process the mbuf */
- if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
- struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
- /* XXX gettdb() should really be called at spltdb(). */
- /* XXX this is splsoftnet(), currently they are the same. */
- tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
- free(m->m_pkthdr.tdbi, M_TEMP);
- m->m_pkthdr.tdbi = NULL;
- }
-#endif /* IPSEC */
/*
* Before we do ANYTHING, we have to figure out if it's TCP/IPv6 or
* TCP/IPv4.
@@ -424,6 +423,10 @@ tcp_input(m, va_alist)
af = AF_INET;
break;
default:
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return; /*EAFNOSUPPORT*/
}
@@ -436,6 +439,10 @@ tcp_input(m, va_alist)
case AF_INET:
#ifdef DIAGNOSTIC
if (iphlen < sizeof(struct ip)) {
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return;
}
@@ -446,6 +453,10 @@ tcp_input(m, va_alist)
iphlen = sizeof(struct ip);
#else
printf("extension headers are not allowed\n");
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return;
#endif
@@ -456,6 +467,10 @@ tcp_input(m, va_alist)
#ifdef DIAGNOSTIC
if (iphlen < sizeof(struct ip6_hdr)) {
m_freem(m);
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
#endif /* DIAGNOSTIC */
@@ -465,6 +480,10 @@ tcp_input(m, va_alist)
iphlen = sizeof(struct ip6_hdr);
#else
printf("extension headers are not allowed\n");
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return;
#endif
@@ -472,6 +491,10 @@ tcp_input(m, va_alist)
break;
#endif
default:
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
return;
}
@@ -480,6 +503,10 @@ tcp_input(m, va_alist)
m = m_pullup2(m, iphlen + sizeof(struct tcphdr));
if (m == 0) {
tcpstat.tcps_rcvshort++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
}
@@ -567,6 +594,10 @@ tcp_input(m, va_alist)
if (m->m_len < iphlen + off) {
if ((m = m_pullup2(m, iphlen + off)) == 0) {
tcpstat.tcps_rcvshort++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
switch (af) {
@@ -779,30 +810,24 @@ findpcb:
}
#ifdef IPSEC
- /* Check if this socket requires security for incoming packets */
- if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
- !(m->m_flags & M_AUTH)) ||
- (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
- !(m->m_flags & M_CONF))) {
-#ifdef notyet
- switch (af) {
-#ifdef INET6
- case AF_INET6:
- icmp6_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
- break;
-#endif /* INET6 */
- case AF_INET:
- icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
- break;
- }
-#endif /* notyet */
- tcpstat.tcps_rcvnosec++;
+ s = splnet();
+ if (tdbi == NULL)
+ tdb = NULL;
+ else
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+
+ ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
+ tdb, inp);
+ splx(s);
+
+ if (tdbi)
+ free(tdbi, M_TEMP);
+ tdbi = NULL;
+
+ /* Error or otherwise drop-packet indication */
+ if (error)
goto drop;
- }
- /* Use tdb_bind_out for this inp's outbound communication */
- if (tdb)
- tdb_add_inp(tdb, inp);
-#endif /*IPSEC */
+#endif /* IPSEC */
/*
* Segment received on connection.
@@ -2080,6 +2105,9 @@ dropwithreset:
return;
drop:
+ if (tdbi)
+ free(tdbi, M_TEMP);
+
/*
* Drop space held by incoming segment and return.
*/
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index c0646e89a2e..bea80fb06f2 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tcp_usrreq.c,v 1.46 2000/07/11 16:53:22 provos Exp $ */
+/* $OpenBSD: tcp_usrreq.c,v 1.47 2000/09/19 03:20:59 angelos Exp $ */
/* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
/*
@@ -82,10 +82,6 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#include <netinet/tcp_debug.h>
#include <dev/rndvar.h>
-#ifdef IPSEC
-extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
-#endif
-
/*
* TCP protocol interface to socket abstraction.
*/
@@ -393,9 +389,7 @@ tcp_usrreq(so, req, m, nam, control)
*/
case PRU_SEND:
#ifdef IPSEC
- error = check_ipsec_policy(inp, 0);
- if (error)
- break;
+ /* XXX Find IPsec TDB */
#endif
sbappend(&so->so_snd, m);
error = tcp_output(tp);
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 7da01d6763e..1c4d2fa888f 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: udp_usrreq.c,v 1.47 2000/07/27 06:29:09 itojun Exp $ */
+/* $OpenBSD: udp_usrreq.c,v 1.48 2000/09/19 03:21:00 angelos Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */
/*
@@ -77,8 +77,6 @@ didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
#ifdef IPSEC
#include <netinet/ip_ipsp.h>
-
-extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#endif
#include <machine/stdarg.h>
@@ -93,6 +91,8 @@ extern int check_ipsec_policy __P((struct inpcb *, u_int32_t));
#include <netinet/icmp6.h>
#include <netinet6/ip6protosw.h>
+#define PI_MAGIC 0xdeadbeef /* XXX the horror! */
+
extern int ip6_defhlim;
#endif /* INET6 */
@@ -174,7 +174,13 @@ udp_input(m, va_alist)
struct ip6_hdr *ipv6;
#endif /* INET6 */
#ifdef IPSEC
- struct tdb *tdb = NULL;
+ struct tdb_ident *tdbi;
+ struct tdb *tdb;
+ int error, s;
+
+ tdbi = (struct tdb_ident *) m->m_pkthdr.tdbi;
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
#endif /* IPSEC */
va_start(ap, m);
@@ -183,18 +189,6 @@ udp_input(m, va_alist)
udpstat.udps_ipackets++;
-#ifdef IPSEC
- /* Save the last SA which was used to process the mbuf */
- if ((m->m_flags & (M_CONF|M_AUTH)) && m->m_pkthdr.tdbi) {
- struct tdb_ident *tdbi = m->m_pkthdr.tdbi;
- /* XXX gettdb() should really be called at spltdb(). */
- /* XXX this is splsoftnet(), currently they are the same. */
- tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
- free(m->m_pkthdr.tdbi, M_TEMP);
- m->m_pkthdr.tdbi = NULL;
- }
-#endif /* IPSEC */
-
switch (mtod(m, struct ip *)->ip_v) {
case 4:
ip = mtod(m, struct ip *);
@@ -237,6 +231,10 @@ udp_input(m, va_alist)
if (m->m_len < iphlen + sizeof(struct udphdr)) {
if ((m = m_pullup2(m, iphlen + sizeof(struct udphdr))) == 0) {
udpstat.udps_hdrops++;
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
#ifdef INET6
@@ -305,6 +303,10 @@ udp_input(m, va_alist)
if ((uh->uh_sum = in_cksum(m, len + sizeof (struct ip))) != 0) {
udpstat.udps_badsum++;
m_freem(m);
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
} else
@@ -478,6 +480,10 @@ udp_input(m, va_alist)
goto bad;
}
sorwakeup(last);
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
/*
@@ -522,31 +528,37 @@ udp_input(m, va_alist)
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT,
0, 0);
}
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
return;
}
}
#ifdef IPSEC
- /* Check if this socket requires security for incoming packets */
- if ((inp->inp_seclevel[SL_AUTH] >= IPSEC_LEVEL_REQUIRE &&
- !(m->m_flags & M_AUTH)) ||
- (inp->inp_seclevel[SL_ESP_TRANS] >= IPSEC_LEVEL_REQUIRE &&
- !(m->m_flags & M_CONF))) {
-#ifdef notyet
-#ifdef INET6
- if (ipv6)
- ipv6_icmp_error(m, ICMPV6_BLAH, ICMPV6_BLAH, 0);
- else
-#endif /* INET6 */
- icmp_error(m, ICMP_BLAH, ICMP_BLAH, 0, 0);
- m = NULL;
-#endif /* notyet */
- udpstat.udps_nosec++;
+#define PI_MAGIC 0xdeadbeef /* XXX the horror! */
+ tdbi = (struct tdb_ident *) m->m_pkthdr.tdbi;
+ if (tdbi == (void *) PI_MAGIC)
+ tdbi = NULL;
+
+ s = splnet();
+ if (tdbi == NULL)
+ tdb = NULL;
+ else
+ tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
+
+ ipsp_spd_lookup(m, srcsa.sa.sa_family, iphlen, &error,
+ IPSP_DIRECTION_IN, tdb, inp);
+ splx(s);
+
+ if (tdbi)
+ free(tdbi, M_TEMP);
+ tdbi = NULL;
+
+ /* Error or otherwise drop-packet indication */
+ if (error)
goto bad;
- }
- /* Use tdb_bind_out for this inp's outbound communication */
- if (tdb)
- tdb_add_inp(tdb, inp);
#endif /*IPSEC */
opts = NULL;
@@ -590,6 +602,10 @@ udp_input(m, va_alist)
sorwakeup(inp->inp_socket);
return;
bad:
+#ifdef IPSEC
+ if (tdbi)
+ free(tdbi, M_TEMP);
+#endif /* IPSEC */
m_freem(m);
if (opts)
m_freem(opts);
@@ -1161,9 +1177,7 @@ udp_usrreq(so, req, m, addr, control)
case PRU_SEND:
#ifdef IPSEC
- error = check_ipsec_policy(inp,0);
- if (error)
- return (error);
+ /* XXX Find IPsec TDB */
#endif
#ifdef INET6
if (inp->inp_flags & INP_IPV6)