summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1997-07-27 23:30:38 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1997-07-27 23:30:38 +0000
commitec6476191b05b8fefe66b6c9fc075b15ee809be6 (patch)
tree365e92dc2a1853ddda0cfc0d63b869895d9d03b7 /sys/netinet
parentbe30223d21a88e015111990b2ce8654b471005ba (diff)
expiration messages, fixes, updates, all sorts of things
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_ah.c77
-rw-r--r--sys/netinet/ip_ah_new.c65
-rw-r--r--sys/netinet/ip_ah_old.c60
-rw-r--r--sys/netinet/ip_esp.c75
-rw-r--r--sys/netinet/ip_esp_old.c62
-rw-r--r--sys/netinet/ip_ipsp.c299
-rw-r--r--sys/netinet/ip_ipsp.h34
-rw-r--r--sys/netinet/ip_output.c124
8 files changed, 751 insertions, 45 deletions
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index 20cbb82c5bd..f67359bb4f8 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.c,v 1.9 1997/07/18 18:09:51 provos Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.10 1997/07/27 23:30:33 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -71,8 +71,9 @@ void
ah_input(register struct mbuf *m, int iphlen)
{
struct ifqueue *ifq = NULL;
- struct ip *ipo, ipn;
struct ah_old *ahp, ahn;
+ struct expiration *exp;
+ struct ip *ipo, ipn;
struct tdb *tdbp;
int s;
@@ -135,10 +136,53 @@ ah_input(register struct mbuf *m, int iphlen)
m->m_pkthdr.rcvif = &enc_softc;
- /* Register first use */
+ /* Register first use, setup expiration timer */
if (tdbp->tdb_first_use == 0)
- tdbp->tdb_first_use = time.tv_sec;
+ {
+ tdbp->tdb_first_use = time.tv_sec;
+
+ if (tdbp->tdb_flags & TDBF_FIRSTUSE)
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING,
+ "ah_input(): out of memory for expiration timer");
+ ahstat.ahs_hdrops++;
+ m_freem(m);
+ return;
+ }
+
+ exp->exp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ exp->exp_spi = tdbp->tdb_spi;
+ exp->exp_sproto = tdbp->tdb_sproto;
+ exp->exp_timeout = tdbp->tdb_first_use + tdbp->tdb_exp_first_use;
+
+ put_expiration(exp);
+ }
+ if ((tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE) &&
+ (tdbp->tdb_soft_first_use <= tdbp->tdb_exp_first_use))
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING,
+ "ah_input(): out of memory for expiration timer");
+ ahstat.ahs_hdrops++;
+ m_freem(m);
+ return;
+ }
+
+ exp->exp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ exp->exp_spi = tdbp->tdb_spi;
+ exp->exp_sproto = tdbp->tdb_sproto;
+ exp->exp_timeout = tdbp->tdb_first_use + tdbp->tdb_soft_first_use;
+
+ put_expiration(exp);
+ }
+ }
+
ipn = *ipo;
ahn = *ahp;
@@ -150,6 +194,31 @@ ah_input(register struct mbuf *m, int iphlen)
return;
}
+ ipo = mtod(m, struct ip *);
+ if (ipo->ip_p == IPPROTO_IPIP) /* IP-in-IP encapsulation */
+ {
+ /* Encapsulating SPI */
+ if (tdbp->tdb_osrc.s_addr && tdbp->tdb_odst.s_addr)
+ {
+ if (tdbp->tdb_flags & TDBF_UNIQUE)
+ if ((ipn.ip_src.s_addr != ipo->ip_src.s_addr) ||
+ (ipn.ip_dst.s_addr != ipo->ip_dst.s_addr))
+ {
+ log(LOG_ALERT, "ah_input(): AH-tunnel with different internal addresses %x/%x, SA %08x/%x\n", ipo->ip_src, ipo->ip_dst, tdbp->tdb_spi, tdbp->tdb_dst);
+ m_freem(m);
+ ahstat.ahs_hdrops++;
+ return;
+ }
+ }
+ else /* So we're paranoid */
+ {
+ log(LOG_ALERT, "ah_input(): AH-tunnel used when expecting AH-transport, SA %08x/%x", tdbp->tdb_spi, tdbp->tdb_dst);
+ m_freem(m);
+ ahstat.ahs_hdrops++;
+ return;
+ }
+ }
+
/*
* Interface pointer is already in first mbuf; chop off the
* `outer' header and reschedule.
diff --git a/sys/netinet/ip_ah_new.c b/sys/netinet/ip_ah_new.c
index 58c647faa08..3ab1c619eaf 100644
--- a/sys/netinet/ip_ah_new.c
+++ b/sys/netinet/ip_ah_new.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah_new.c,v 1.5 1997/07/24 01:37:10 deraadt Exp $ */
+/* $OpenBSD: ip_ah_new.c,v 1.6 1997/07/27 23:30:34 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -61,6 +61,8 @@
#include <netinet/ip_ah.h>
#include <sys/syslog.h>
+extern void encap_sendnotify(int, struct tdb *);
+
/*
* ah_new_attach() is called from the transformation initialization code.
* It just returns.
@@ -589,6 +591,35 @@ ah_new_input(struct mbuf *m, struct tdb *tdb)
tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
ahstat.ahs_ibytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return m;
}
@@ -889,8 +920,38 @@ ah_new_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
/* Update the counters */
tdb->tdb_cur_packets++;
- tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) - AH_NEW_FLENGTH;
+ tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) -
+ AH_NEW_FLENGTH;
ahstat.ahs_obytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) - AH_NEW_FLENGTH;
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return 0;
}
diff --git a/sys/netinet/ip_ah_old.c b/sys/netinet/ip_ah_old.c
index 7c310158668..e680b8c3f22 100644
--- a/sys/netinet/ip_ah_old.c
+++ b/sys/netinet/ip_ah_old.c
@@ -59,6 +59,8 @@
#include <netinet/ip_ah.h>
#include <sys/syslog.h>
+extern void encap_sendnotify(int, struct tdb *);
+
/*
* ah_old_attach() is called from the transformation initialization code.
*/
@@ -483,6 +485,35 @@ ah_old_input(struct mbuf *m, struct tdb *tdb)
tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
ahstat.ahs_ibytes += ntohs(ip->ip_len) - (ip->ip_hl << 2);
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return m;
}
@@ -778,5 +809,34 @@ ah_old_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
ahstat.ahs_obytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) -
AH_OLD_FLENGTH - alen;
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return 0;
}
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c
index d7cac3c9359..c1b605f6f97 100644
--- a/sys/netinet/ip_esp.c
+++ b/sys/netinet/ip_esp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp.c,v 1.9 1997/07/18 18:09:54 provos Exp $ */
+/* $OpenBSD: ip_esp.c,v 1.10 1997/07/27 23:30:35 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -70,6 +70,7 @@ void
esp_input(register struct mbuf *m, int iphlen)
{
struct ifqueue *ifq = NULL;
+ struct expiration *exp;
struct ip *ipo, ipn;
struct tdb *tdbp;
u_int32_t spi;
@@ -134,10 +135,53 @@ esp_input(register struct mbuf *m, int iphlen)
m->m_pkthdr.rcvif = &enc_softc;
- /* Register first use */
+ /* Register first use, setup expiration timer */
if (tdbp->tdb_first_use == 0)
- tdbp->tdb_first_use = time.tv_sec;
+ {
+ tdbp->tdb_first_use = time.tv_sec;
+
+ if (tdbp->tdb_flags & TDBF_FIRSTUSE)
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING,
+ "esp_input(): out of memory for expiration timer");
+ espstat.esps_hdrops++;
+ m_freem(m);
+ return;
+ }
+
+ exp->exp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ exp->exp_spi = tdbp->tdb_spi;
+ exp->exp_sproto = tdbp->tdb_sproto;
+ exp->exp_timeout = tdbp->tdb_first_use + tdbp->tdb_exp_first_use;
+
+ put_expiration(exp);
+ }
+ if ((tdbp->tdb_flags & TDBF_SOFT_FIRSTUSE) &&
+ (tdbp->tdb_soft_first_use <= tdbp->tdb_exp_first_use))
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING,
+ "esp_input(): out of memory for expiration timer");
+ espstat.esps_hdrops++;
+ m_freem(m);
+ return;
+ }
+
+ exp->exp_dst.s_addr = tdbp->tdb_dst.s_addr;
+ exp->exp_spi = tdbp->tdb_spi;
+ exp->exp_sproto = tdbp->tdb_sproto;
+ exp->exp_timeout = tdbp->tdb_first_use + tdbp->tdb_soft_first_use;
+
+ put_expiration(exp);
+ }
+ }
+
ipn = *ipo;
m = (*(tdbp->tdb_xform->xf_input))(m, tdbp);
@@ -149,6 +193,31 @@ esp_input(register struct mbuf *m, int iphlen)
return;
}
+ ipo = mtod(m, struct ip *);
+ if (ipo->ip_p == IPPROTO_IPIP) /* IP-in-IP encapsulation */
+ {
+ /* Encapsulating SPI */
+ if (tdbp->tdb_osrc.s_addr && tdbp->tdb_odst.s_addr)
+ {
+ if (tdbp->tdb_flags & TDBF_UNIQUE)
+ if ((ipn.ip_src.s_addr != ipo->ip_src.s_addr) ||
+ (ipn.ip_dst.s_addr != ipo->ip_dst.s_addr))
+ {
+ log(LOG_ALERT, "esp_input(): ESP-tunnel with different internal addresses %x/%x, SA %08x/%x\n", ipo->ip_src, ipo->ip_dst, tdbp->tdb_spi, tdbp->tdb_dst);
+ m_freem(m);
+ espstat.esps_hdrops++;
+ return;
+ }
+ }
+ else /* So we're paranoid */
+ {
+ log(LOG_ALERT, "esp_input(): ESP-tunnel used when expecting ESP-transport, SA %08x/%x", tdbp->tdb_spi, tdbp->tdb_dst);
+ m_freem(m);
+ espstat.esps_hdrops++;
+ return;
+ }
+ }
+
/*
* Interface pointer is already in first mbuf; chop off the
* `outer' header and reschedule.
diff --git a/sys/netinet/ip_esp_old.c b/sys/netinet/ip_esp_old.c
index 3945ec0ebe9..e8bb76bfc0f 100644
--- a/sys/netinet/ip_esp_old.c
+++ b/sys/netinet/ip_esp_old.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_esp_old.c,v 1.3 1997/07/18 18:09:55 provos Exp $ */
+/* $OpenBSD: ip_esp_old.c,v 1.4 1997/07/27 23:30:36 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -65,6 +65,8 @@ extern void des_ecb3_encrypt(caddr_t, caddr_t, caddr_t, caddr_t, caddr_t, int);
extern void des_ecb_encrypt(caddr_t, caddr_t, caddr_t, int);
extern void des_set_key(caddr_t, caddr_t);
+extern encap_sendnotify(int, struct tdb *);
+
int
esp_old_attach()
{
@@ -482,6 +484,35 @@ esp_old_input(struct mbuf *m, struct tdb *tdb)
tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) + blk[6] + 2;
espstat.esps_ibytes += ntohs(ip->ip_len) - (ip->ip_hl << 2) + blk[6] + 2;
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return m;
}
@@ -729,6 +760,35 @@ esp_old_output(struct mbuf *m, struct sockaddr_encap *gw, struct tdb *tdb,
tdb->tdb_cur_bytes += rlen + padding;
espstat.esps_obytes += rlen + padding;
+ /* Notify on expiration */
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_soft_packets)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_PACKETS;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_BYTES;
+ }
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ if (tdb->tdb_cur_packets >= tdb->tdb_exp_packets)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_BYTES)
+ if (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
return 0;
}
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c
index c20916e13bf..a4f4238d37a 100644
--- a/sys/netinet/ip_ipsp.c
+++ b/sys/netinet/ip_ipsp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.c,v 1.16 1997/07/24 01:45:29 deraadt Exp $ */
+/* $OpenBSD: ip_ipsp.c,v 1.17 1997/07/27 23:30:36 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -64,6 +64,9 @@ int tdb_init __P((struct tdb *, struct mbuf *));
int ipsp_kern __P((int, char **, int));
int encdebug = 0;
+u_int32_t kernfs_epoch = 0;
+
+extern void encap_sendnotify(int, struct tdb *);
/*
* This is the proper place to define the various encapsulation transforms.
@@ -137,7 +140,8 @@ reserve_spi(u_int32_t tspi, struct in_addr src, u_int8_t proto, int *errval)
tdbp->tdb_dst = src;
tdbp->tdb_sproto = proto;
tdbp->tdb_flags |= TDBF_INVALID;
-
+ tdbp->tdb_epoch = kernfs_epoch - 1;
+
puttdb(tdbp);
return spi;
@@ -182,6 +186,182 @@ get_flow(void)
return flow;
}
+struct expiration *
+get_expiration(void)
+{
+ struct expiration *exp;
+
+ MALLOC(exp, struct expiration *, sizeof(struct expiration), M_TDB,
+ M_WAITOK);
+ if (exp == (struct expiration *) NULL)
+ return (struct expiration *) NULL;
+
+ bzero(exp, sizeof(struct expiration));
+
+ return exp;
+}
+
+void
+cleanup_expirations(struct in_addr dst, u_int32_t spi, u_int8_t sproto)
+{
+ struct expiration *exp, *nexp;
+
+ for (exp = explist; exp; exp = exp->exp_next)
+ if ((exp->exp_dst.s_addr == dst.s_addr) &&
+ (exp->exp_spi == spi) && (exp->exp_sproto == sproto))
+ {
+ /* Link previous to next */
+ if (exp->exp_prev == (struct expiration *) NULL)
+ explist = exp->exp_next;
+ else
+ exp->exp_prev->exp_next = exp->exp_next;
+
+ /* Link next (if it exists) to previous */
+ if (exp->exp_next != (struct expiration *) NULL)
+ exp->exp_next->exp_prev = exp->exp_prev;
+
+ nexp = exp;
+ exp = exp->exp_prev;
+ free(nexp, M_TDB);
+ }
+}
+
+void
+handle_expirations(void *arg)
+{
+ struct expiration *exp;
+ struct tdb *tdb;
+
+ if (explist == (struct expiration *) NULL)
+ return;
+
+ while (1)
+ {
+ exp = explist;
+
+ if (exp == (struct expiration *) NULL)
+ return;
+ else
+ if (exp->exp_timeout > time.tv_sec)
+ break;
+
+ /* Advance pointer */
+ explist = explist->exp_next;
+ if (explist)
+ explist->exp_prev = NULL;
+
+ tdb = gettdb(exp->exp_spi, exp->exp_dst, exp->exp_sproto);
+ if (tdb == (struct tdb *) NULL)
+ {
+ free(exp, M_TDB);
+ continue; /* TDB is gone, ignore this */
+ }
+
+ /* Soft expirations */
+ if (tdb->tdb_flags & TDBF_SOFT_TIMER)
+ if (tdb->tdb_soft_timeout <= time.tv_sec)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_TIMER;
+ }
+ else
+ if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
+ if (tdb->tdb_first_use + tdb->tdb_soft_first_use <=
+ time.tv_sec)
+ {
+ encap_sendnotify(NOTIFY_SOFT_EXPIRE, tdb);
+ tdb->tdb_flags &= ~TDBF_SOFT_FIRSTUSE;
+ }
+
+ /* Hard expirations */
+ if (tdb->tdb_flags & TDBF_TIMER)
+ if (tdb->tdb_exp_timeout <= time.tv_sec)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+ else
+ if (tdb->tdb_flags & TDBF_FIRSTUSE)
+ if (tdb->tdb_first_use + tdb->tdb_exp_first_use <=
+ time.tv_sec)
+ {
+ encap_sendnotify(NOTIFY_HARD_EXPIRE, tdb);
+ tdb_delete(tdb, 0);
+ }
+
+ free(exp, M_TDB);
+ }
+
+ if (explist)
+ timeout(handle_expirations, (void *) NULL,
+ hz * (explist->exp_timeout - time.tv_sec));
+}
+
+void
+put_expiration(struct expiration *exp)
+{
+ struct expiration *expt;
+ int reschedflag = 0;
+
+ if (exp == (struct expiration *) NULL)
+ {
+#ifdef ENCDEBUG
+ if (encdebug)
+ log(LOG_WARN, "put_expiration(): NULL argument");
+#endif /* ENCDEBUG */
+ return;
+ }
+
+ if (explist == (struct expiration *) NULL)
+ {
+ explist = exp;
+ reschedflag = 1;
+ }
+ else
+ if (explist->exp_timeout > exp->exp_timeout)
+ {
+ exp->exp_next = explist;
+ explist->exp_prev = exp;
+ explist = exp;
+ reschedflag = 2;
+ }
+ else
+ {
+ for (expt = explist; expt->exp_next; expt = expt->exp_next)
+ if (expt->exp_next->exp_timeout > exp->exp_timeout)
+ {
+ expt->exp_next->exp_prev = exp;
+ exp->exp_next = expt->exp_next;
+ expt->exp_next = exp;
+ exp->exp_prev = expt;
+ break;
+ }
+
+ if (expt->exp_next == (struct expiration *) NULL)
+ {
+ expt->exp_next = exp;
+ exp->exp_prev = expt;
+ }
+ }
+
+ switch (reschedflag)
+ {
+ case 1:
+ timeout(handle_expirations, (void *) NULL,
+ hz * (explist->exp_timeout - time.tv_sec));
+ break;
+
+ case 2:
+ untimeout(handle_expirations, (void *) NULL);
+ timeout(handle_expirations, (void *) NULL,
+ hz * (explist->exp_timeout - time.tv_sec));
+ break;
+
+ default:
+ break;
+ }
+}
+
struct flow *
find_flow(struct in_addr src, struct in_addr srcmask, struct in_addr dst,
struct in_addr dstmask, u_int8_t proto, u_int16_t sport,
@@ -300,7 +480,9 @@ tdb_delete(struct tdb *tdbp, int delchain)
for (flow = tdbp->tdb_flow; flow; flow = tdbp->tdb_flow)
delete_flow(flow, tdbp);
-
+
+ cleanup_expirations(tdbp->tdb_dst, tdbp->tdb_spi, tdbp->tdb_sproto);
+
FREE(tdbp, M_TDB);
if (delchain && tdbpp)
@@ -319,25 +501,124 @@ tdb_init(struct tdb *tdbp, struct mbuf *m)
em = mtod(m, struct encap_msghdr *);
alg = em->em_alg;
+ /* Record establishment time */
+ tdbp->tdb_established = time.tv_sec;
+
+ tdbp->tdb_epoch = kernfs_epoch - 1;
+
for (xsp = xformsw; xsp < xformswNXFORMSW; xsp++)
if (xsp->xf_type == alg)
return (*(xsp->xf_init))(tdbp, xsp, m);
log(LOG_ERR, "tdb_init(): no alg %d for spi %08x, addr %x, proto %d", alg,
ntohl(tdbp->tdb_spi), tdbp->tdb_dst.s_addr, tdbp->tdb_sproto);
-
- /* Record establishment time */
- tdbp->tdb_established = time.tv_sec;
-
- m_freem(m);
+
return EINVAL;
}
/*
- * XXX This should change to something cleaner.
+ * Used by kernfs
*/
int
ipsp_kern(int off, char **bufp, int len)
{
+ static char buffer[IPSEC_KERNFS_BUFSIZE];
+ struct tdb *tdb;
+ struct flow *fl;
+ int l, i;
+
+ if (off == 0)
+ kernfs_epoch++;
+
+ if (bufp == NULL)
+ return 0;
+
+ bzero(buffer, IPSEC_KERNFS_BUFSIZE);
+
+ *bufp = buffer;
+
+ for (i = 0; i < TDB_HASHMOD; i++)
+ for (tdb = tdbh[i]; tdb; tdb = tdb->tdb_hnext)
+ if (tdb->tdb_epoch != kernfs_epoch)
+ {
+ tdb->tdb_epoch = kernfs_epoch;
+
+ l = sprintf(buffer, "SPI = %08x, Destination = %s, Sproto = %d\n",
+ ntohl(tdb->tdb_spi), inet_ntoa(tdb->tdb_dst),
+ tdb->tdb_sproto);
+
+ l += sprintf(buffer + l, "\testablished %d seconds ago\n",
+ time.tv_sec - tdb->tdb_established);
+
+ l += sprintf(buffer + l, "\tsrc = %s, flags = %08x, SAtype = %d\n",
+ inet_ntoa(tdb->tdb_src), tdb->tdb_flags,
+ tdb->tdb_satype);
+
+ if (tdb->tdb_xform)
+ l += sprintf(buffer + l, "\txform = <%s>\n",
+ tdb->tdb_xform->xf_name);
+ else
+ l += sprintf(buffer + l, "\txform = <(null)>\n");
+
+ l += sprintf(buffer + l, "\tOSrc = %s", inet_ntoa(tdb->tdb_osrc));
+
+ l += sprintf(buffer + l, " ODst = %s, TTL = %d\n",
+ inet_ntoa(tdb->tdb_odst), tdb->tdb_ttl);
+
+ if (tdb->tdb_onext)
+ l += sprintf(buffer + l, "\tNext (on output) SA: SPI = %08x, Destination = %s, Sproto = %d\n", tdb->tdb_onext->tdb_spi, inet_ntoa(tdb->tdb_onext->tdb_dst), tdb->tdb_onext->tdb_sproto);
+
+ if (tdb->tdb_inext)
+ l += sprintf(buffer + l, "\tNext (on input) SA: SPI = %08x, Destination = %s, Sproto = %d\n", tdb->tdb_inext->tdb_spi, inet_ntoa(tdb->tdb_inext->tdb_dst), tdb->tdb_inext->tdb_sproto);
+
+ /* XXX We can reuse variable i, we're not going to loop again */
+ for (i = 0, fl = tdb->tdb_flow; fl; fl = fl->flow_next)
+ i++;
+
+ l += sprintf(buffer + l, "\t%d flows counted (use netstat -r for more information)\n", i);
+
+ l += sprintf(buffer + l, "\tExpirations:\n");
+
+ if (tdb->tdb_flags & TDBF_TIMER)
+ l += sprintf(buffer + l, "\t\tHard expiration(1) in %d seconds\n",
+ tdb->tdb_exp_timeout - time.tv_sec);
+
+ if (tdb->tdb_flags & TDBF_SOFT_TIMER)
+ l += sprintf(buffer + l, "\t\tSoft expiration(1) in %d seconds\n",
+ tdb->tdb_soft_timeout - time.tv_sec);
+
+ if (tdb->tdb_flags & TDBF_BYTES)
+ l += sprintf(buffer + l, "\t\tHard expiration after %qd bytes (currently %qd bytes processed)\n", tdb->tdb_exp_bytes, tdb->tdb_cur_bytes);
+
+ if (tdb->tdb_flags & TDBF_SOFT_BYTES)
+ l += sprintf(buffer + l, "\t\tSoft expiration after %qd bytes (currently %qd bytes processed)\n", tdb->tdb_soft_bytes, tdb->tdb_cur_bytes);
+
+ if (tdb->tdb_flags & TDBF_PACKETS)
+ l += sprintf(buffer + l, "\t\tHard expiration after %qd packets (currently %qd packets processed)\n", tdb->tdb_exp_packets, tdb->tdb_cur_packets);
+
+ if (tdb->tdb_flags & TDBF_SOFT_PACKETS)
+ l += sprintf(buffer + l, "\t\tSoft expiration after %qd packets (currently %qd packets processed)\n", tdb->tdb_soft_packets, tdb->tdb_cur_packets);
+
+ if (tdb->tdb_flags & TDBF_FIRSTUSE)
+ l += sprintf(buffer + l, "\t\tHard expiration(2) in %d seconds\n",
+ (tdb->tdb_established + tdb->tdb_exp_first_use) -
+ time.tv_sec);
+
+ if (tdb->tdb_flags & TDBF_SOFT_FIRSTUSE)
+ l += sprintf(buffer + l, "\t\tSoft expiration(2) in %d seconds\n",
+ (tdb->tdb_established + tdb->tdb_soft_first_use) -
+ time.tv_sec);
+
+ if (!(tdb->tdb_flags & (TDBF_TIMER | TDBF_SOFT_TIMER | TDBF_BYTES |
+ TDBF_SOFT_PACKETS | TDBF_PACKETS |
+ TDBF_SOFT_BYTES | TDBF_FIRSTUSE |
+ TDBF_SOFT_FIRSTUSE)))
+ l += sprintf(buffer + l, "\t\t(none)\n");
+
+ l += sprintf(buffer + l, "\n");
+
+ return l;
+ }
+
return 0;
}
diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h
index 4f5e25b4a50..db931990557 100644
--- a/sys/netinet/ip_ipsp.h
+++ b/sys/netinet/ip_ipsp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipsp.h,v 1.13 1997/07/15 23:11:10 provos Exp $ */
+/* $OpenBSD: ip_ipsp.h,v 1.14 1997/07/27 23:30:37 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -27,6 +27,16 @@
* IPSP global definitions.
*/
+struct expiration
+{
+ u_int32_t exp_timeout;
+ struct in_addr exp_dst;
+ u_int32_t exp_spi;
+ u_int8_t exp_sproto;
+ struct expiration *exp_next;
+ struct expiration *exp_prev;
+};
+
struct flow
{
struct flow *flow_next; /* Next in flow chain */
@@ -56,14 +66,12 @@ struct tdb /* tunnel descriptor block */
#define TDBF_PACKETS 0x00008 /* Check the packet counters */
#define TDBF_INVALID 0x00010 /* This SPI is not valid yet/anymore */
#define TDBF_FIRSTUSE 0x00020 /* Expire after first use */
-#define TDBF_RELATIVE 0x00040 /* Expire after X secs from establ. */
+#define TDBF_TUNNELING 0x00040 /* Do IP-in-IP encapsulation */
#define TDBF_SOFT_TIMER 0x00080 /* Soft expiration */
#define TDBF_SOFT_BYTES 0x00100 /* Soft expiration */
#define TDBF_SOFT_PACKETS 0x00200 /* Soft expiration */
#define TDBF_SOFT_FIRSTUSE 0x00400 /* Soft expiration */
-#define TDBF_SOFT_RELATIVE 0x00800 /* Soft expiration */
-#define TDBF_TUNNELING 0x01000 /* Do IP-in-IP encapsulation */
-#define TDBF_SAME_TTL 0x02000 /* Keep the packet TTL, in tunneling */
+#define TDBF_SAME_TTL 0x00800 /* Keep the packet TTL, in tunneling */
u_int64_t tdb_exp_packets; /* Expire after so many packets s|r */
u_int64_t tdb_soft_packets; /* Expiration warning */
u_int64_t tdb_cur_packets; /* Current number of packets s|r'ed */
@@ -73,9 +81,6 @@ struct tdb /* tunnel descriptor block */
u_int64_t tdb_exp_timeout; /* When does the SPI expire */
u_int64_t tdb_soft_timeout; /* Send a soft-expire warning */
u_int64_t tdb_established; /* When was the SPI established */
- u_int64_t tdb_soft_relative ; /* Soft warning */
- u_int64_t tdb_exp_relative; /* Expire if tdb_established +
- tdb_exp_relative <= curtime */
u_int64_t tdb_first_use; /* When was it first used */
u_int64_t tdb_soft_first_use; /* Soft warning */
u_int64_t tdb_exp_first_use; /* Expire if tdb_first_use +
@@ -89,9 +94,11 @@ struct tdb /* tunnel descriptor block */
* tunneling */
caddr_t tdb_xdata; /* transformation data (opaque) */
struct flow *tdb_flow; /* Which flows use this SA */
+
u_int8_t tdb_ttl; /* TTL used in tunneling */
u_int8_t tdb_sproto; /* IPsec protocol */
- u_int8_t tdb_foo[2]; /* Alignment */
+ u_int16_t tdb_satype; /* Alignment */
+ u_int32_t tdb_epoch; /* Used by the kernfs interface */
};
#define TDB_HASHMOD 257
@@ -126,6 +133,7 @@ struct xformsw
#define XFT_CONF 0x0100
#define IPSEC_ZEROES_SIZE 64
+#define IPSEC_KERNFS_BUFSIZE 4096
#if BYTE_ORDER == LITTLE_ENDIAN
static __inline u_int64_t
@@ -165,7 +173,9 @@ extern unsigned char ipseczeroes[];
extern int encdebug;
struct tdb *tdbh[TDB_HASHMOD];
+struct expiration *explist;
extern struct xformsw xformsw[], *xformswNXFORMSW;
+u_int32_t notify_msgids;
/* TDB management routines */
extern u_int32_t reserve_spi(u_int32_t, struct in_addr, u_int8_t, int *);
@@ -173,6 +183,12 @@ extern struct tdb *gettdb(u_int32_t, struct in_addr, u_int8_t);
extern void puttdb(struct tdb *);
extern int tdb_delete(struct tdb *, int);
+/* Expiration management routines */
+extern struct expiration *get_expiration(void);
+extern void put_expiration(struct expiration *);
+extern void handle_expirations(void *);
+extern void cleanup_expirations(struct in_addr, u_int32_t, u_int8_t);
+
/* Flow management routines */
extern struct flow *get_flow(void);
extern void put_flow(struct flow *, struct tdb *);
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index 2b155ffde0d..a4c2c9be706 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_output.c,v 1.18 1997/07/18 18:09:57 provos Exp $ */
+/* $OpenBSD: ip_output.c,v 1.19 1997/07/27 23:30:37 niklas Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
@@ -109,6 +109,7 @@ ip_output(m0, va_alist)
struct mbuf *mp;
struct udphdr *udp;
struct tcphdr *tcp;
+ struct expiration *exp;
#endif
va_start(ap, m0);
@@ -192,14 +193,25 @@ ip_output(m0, va_alist)
goto no_encap;
gw = (struct sockaddr_encap *) (re->re_rt->rt_gateway);
+
+ /*
+ * 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.
+ */
+
+ if ((gw != NULL) && (gw->sen_ipsp_dst.s_addr == 0) &&
+ (gw->sen_ipsp_sproto == 0) && (gw->sen_ipsp_spi == 0))
+ goto no_encap;
+
if (gw == NULL || gw->sen_type != SENT_IPSP) {
#ifdef ENCDEBUG
if (encdebug)
printf("ip_output(): no gw or gw data not IPSP\n");
#endif /* ENCDEBUG */
- m_freem(m);
RTFREE(re->re_rt);
- return EHOSTUNREACH;
+ error = EHOSTUNREACH;
+ goto bad;
}
ip->ip_len = htons((u_short)ip->ip_len);
@@ -207,16 +219,6 @@ ip_output(m0, va_alist)
ip->ip_sum = 0;
/*
- * 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.
- */
-
- if ((gw->sen_ipsp_dst.s_addr == 0) &&
- (gw->sen_ipsp_sproto == 0) && (gw->sen_ipsp_spi == 0))
- goto no_encap;
-
- /*
* 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,
@@ -264,9 +266,53 @@ ip_output(m0, va_alist)
printf("ip_output(): tunneling\n");
#endif /* ENCDEBUG */
- /* Register first use */
+ /*
+ * Register first use,
+ * setup expiration timer
+ */
if (tdb->tdb_first_use == 0)
- tdb->tdb_first_use = time.tv_sec;
+ {
+ tdb->tdb_first_use = time.tv_sec;
+
+ if (tdb->tdb_flags & TDBF_FIRSTUSE)
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING, "ip_output(): out of memory for expiration timer");
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return ENOBUFS;
+ }
+
+ exp->exp_dst.s_addr = tdb->tdb_dst.s_addr;
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_first_use + tdb->tdb_exp_first_use;
+
+ put_expiration(exp);
+ }
+
+ if ((tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) &&
+ (tdb->tdb_soft_first_use <= tdb->tdb_exp_first_use))
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING, "ip_output(): out of memory for expiration timer");
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return ENOBUFS;
+ }
+
+ exp->exp_dst.s_addr = tdb->tdb_dst.s_addr;
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_first_use + tdb->tdb_soft_first_use;
+
+ put_expiration(exp);
+ }
+ }
error = ipe4_output(m, gw, tdb, &mp);
if (mp == NULL)
@@ -284,9 +330,53 @@ ip_output(m0, va_alist)
tdb->tdb_xform->xf_name);
#endif /* ENCDEBUG */
- /* Register first use */
+ /* Register first use, setup expiration timer */
if (tdb->tdb_first_use == 0)
- tdb->tdb_first_use = time.tv_sec;
+ {
+ tdb->tdb_first_use = time.tv_sec;
+
+ if (tdb->tdb_flags & TDBF_FIRSTUSE)
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING, "ip_output(): out of memory for expiration timer");
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return ENOBUFS;
+ }
+
+ exp->exp_dst.s_addr = tdb->tdb_dst.s_addr;
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_first_use +
+ tdb->tdb_exp_first_use;
+
+ put_expiration(exp);
+ }
+
+ if ((tdb->tdb_flags & TDBF_SOFT_FIRSTUSE) &&
+ (tdb->tdb_soft_first_use <=
+ tdb->tdb_exp_first_use))
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ log(LOG_WARNING, "ip_output(): out of memory for expiration timer");
+ m_freem(m);
+ RTFREE(re->re_rt);
+ return ENOBUFS;
+ }
+
+ exp->exp_dst.s_addr = tdb->tdb_dst.s_addr;
+ exp->exp_spi = tdb->tdb_spi;
+ exp->exp_sproto = tdb->tdb_sproto;
+ exp->exp_timeout = tdb->tdb_first_use +
+ tdb->tdb_soft_first_use;
+
+ put_expiration(exp);
+ }
+ }
error = (*(tdb->tdb_xform->xf_output))(m, gw, tdb, &mp);
if (mp == NULL)