diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1997-07-27 23:30:38 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1997-07-27 23:30:38 +0000 |
commit | ec6476191b05b8fefe66b6c9fc075b15ee809be6 (patch) | |
tree | 365e92dc2a1853ddda0cfc0d63b869895d9d03b7 /sys/netinet | |
parent | be30223d21a88e015111990b2ce8654b471005ba (diff) |
expiration messages, fixes, updates, all sorts of things
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/ip_ah.c | 77 | ||||
-rw-r--r-- | sys/netinet/ip_ah_new.c | 65 | ||||
-rw-r--r-- | sys/netinet/ip_ah_old.c | 60 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 75 | ||||
-rw-r--r-- | sys/netinet/ip_esp_old.c | 62 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.c | 299 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 34 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 124 |
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) |