summaryrefslogtreecommitdiff
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
parentbe30223d21a88e015111990b2ce8654b471005ba (diff)
expiration messages, fixes, updates, all sorts of things
-rw-r--r--sys/net/encap.c320
-rw-r--r--sys/net/encap.h44
-rw-r--r--sys/net/route.c4
-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
11 files changed, 1006 insertions, 158 deletions
diff --git a/sys/net/encap.c b/sys/net/encap.c
index 65548e1f236..f0a3b68ead1 100644
--- a/sys/net/encap.c
+++ b/sys/net/encap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: encap.c,v 1.13 1997/07/23 12:07:04 provos Exp $ */
+/* $OpenBSD: encap.c,v 1.14 1997/07/27 23:30:31 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -51,6 +51,7 @@
#include <sys/syslog.h>
void encap_init(void);
+void encap_sendnotify(int, struct tdb *);
int encap_output __P((struct mbuf *, ...));
int encap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *,
struct mbuf *);
@@ -168,9 +169,9 @@ va_dcl
struct in_addr alts, altm;
struct encap_msghdr *emp;
struct tdb *tdbp, *tdbp2;
+ struct expiration *exp;
caddr_t buffer = 0;
struct socket *so;
- struct mbuf *m0;
u_int32_t spi;
va_list ap;
@@ -240,10 +241,16 @@ va_dcl
puttdb(tdbp);
}
else
- if (tdbp->tdb_xform)
- (*tdbp->tdb_xform->xf_zeroize)(tdbp);
+ {
+ if (tdbp->tdb_xform)
+ (*tdbp->tdb_xform->xf_zeroize)(tdbp);
+
+ cleanup_expirations(tdbp->tdb_dst, tdbp->tdb_spi,
+ tdbp->tdb_sproto);
+ }
tdbp->tdb_src = emp->em_src;
+ tdbp->tdb_satype = emp->em_satype;
/* Check if this is an encapsulating SPI */
if (emp->em_osrc.s_addr != 0)
@@ -274,18 +281,6 @@ va_dcl
tdbp->tdb_flags &= (~TDBF_INVALID);
/* Various timers/counters */
- if (emp->em_relative_hard != 0)
- {
- tdbp->tdb_exp_relative = emp->em_relative_hard;
- tdbp->tdb_flags |= TDBF_RELATIVE;
- }
-
- if (emp->em_relative_soft != 0)
- {
- tdbp->tdb_soft_relative = emp->em_relative_soft;
- tdbp->tdb_flags |= TDBF_SOFT_RELATIVE;
- }
-
if (emp->em_first_use_hard != 0)
{
tdbp->tdb_exp_first_use = emp->em_first_use_hard;
@@ -302,12 +297,41 @@ va_dcl
{
tdbp->tdb_exp_timeout = emp->em_expire_hard;
tdbp->tdb_flags |= TDBF_TIMER;
+
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ tdb_delete(tdbp, 0);
+ SENDERR(ENOBUFS);
+ }
+
+ 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 = emp->em_expire_hard;
+ put_expiration(exp);
}
if (emp->em_expire_soft != 0)
{
tdbp->tdb_soft_timeout = emp->em_expire_soft;
tdbp->tdb_flags |= TDBF_SOFT_TIMER;
+
+ if (tdbp->tdb_soft_timeout <= tdbp->tdb_exp_timeout)
+ {
+ exp = get_expiration();
+ if (exp == (struct expiration *) NULL)
+ {
+ tdb_delete(tdbp, 0);
+ SENDERR(ENOBUFS);
+ }
+
+ 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 = emp->em_expire_soft;
+ put_expiration(exp);
+ }
}
if (emp->em_bytes_hard != 0)
@@ -344,10 +368,11 @@ va_dcl
if (emlen != EMT_DELSPI_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst,
+ emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
-
+
error = tdb_delete(tdbp, 0);
if (error)
SENDERR(EINVAL);
@@ -358,10 +383,11 @@ va_dcl
if (emlen != EMT_DELSPICHAIN_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
+ tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst,
+ emp->em_gen_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
-
+
error = tdb_delete(tdbp, 1);
if (error)
SENDERR(EINVAL);
@@ -372,7 +398,8 @@ va_dcl
if (emlen != EMT_GRPSPIS_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_rel_spi, emp->em_rel_dst, emp->em_rel_sproto);
+ tdbp = gettdb(emp->em_rel_spi, emp->em_rel_dst,
+ emp->em_rel_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
@@ -403,59 +430,24 @@ va_dcl
if (buffer)
m_copyback(m, 0, emlen, buffer);
- m0 = m_copy(m, 0, (int) M_COPYALL);
- if (m0 == NULL)
- SENDERR(ENOBUFS);
-
/* Send it back to us */
- if (sbappendaddr(&so->so_rcv, &encap_src, m0,
+ if (sbappendaddr(&so->so_rcv, &encap_src, m,
(struct mbuf *) 0) == 0)
- {
- m_freem(m0);
- SENDERR(ENOBUFS);
- }
+ SENDERR(ENOBUFS);
else
sorwakeup(so); /* wakeup */
+ m = NULL; /* So it's not free'd */
error = 0;
break;
- case EMT_VALIDATE:
- if (emlen != EMT_VALIDATE_FLEN)
- SENDERR(EINVAL);
-
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
- if (tdbp == NULL)
- SENDERR(ENOENT);
-
- /* Clear the INVALID flag */
- tdbp->tdb_flags &= (~TDBF_INVALID);
-
- error = 0;
-
- break;
-
- case EMT_INVALIDATE:
- if (emlen != EMT_INVALIDATE_FLEN)
- SENDERR(EINVAL);
-
- tdbp = gettdb(emp->em_gen_spi, emp->em_gen_dst, emp->em_gen_sproto);
- if (tdbp == NULL)
- SENDERR(ENOENT);
-
- /* Set the INVALID flag */
- tdbp->tdb_flags |= TDBF_INVALID;
-
- error = 0;
-
- break;
-
case EMT_ENABLESPI:
if (emlen != EMT_ENABLESPI_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_ena_spi, emp->em_ena_dst, emp->em_ena_sproto);
+ tdbp = gettdb(emp->em_ena_spi, emp->em_ena_dst,
+ emp->em_ena_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
@@ -484,6 +476,9 @@ va_dcl
if (flow4 != (struct flow *) NULL)
if (!(emp->em_ena_flags & ENABLE_FLAG_REPLACE))
SENDERR(EEXIST);
+ else
+ if (flow3 == flow4)
+ SENDERR(EINVAL);
}
flow = get_flow();
@@ -570,6 +565,46 @@ va_dcl
if (error)
{
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_family = AF_ENCAP;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src.s_addr = flow3->flow_src.s_addr;
+ encapdst.sen_ip_dst.s_addr = flow3->flow_dst.s_addr;
+ encapdst.sen_proto = flow3->flow_proto;
+ encapdst.sen_sport = flow3->flow_sport;
+ encapdst.sen_dport = flow3->flow_dport;
+
+ encapgw.sen_len = SENT_IPSP_LEN;
+ encapgw.sen_family = AF_ENCAP;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp_dst.s_addr = flow3->flow_sa->tdb_dst.s_addr;
+ encapgw.sen_ipsp_spi = flow3->flow_sa->tdb_spi;
+ encapgw.sen_ipsp_sproto = flow3->flow_sa->tdb_sproto;
+
+ encapnetmask.sen_len = SENT_IP4_LEN;
+ encapnetmask.sen_family = AF_ENCAP;
+ encapnetmask.sen_type = SENT_IP4;
+ encapnetmask.sen_ip_src.s_addr = flow3->flow_srcmask.s_addr;
+ encapnetmask.sen_ip_dst.s_addr = flow3->flow_dstmask.s_addr;
+
+ if (flow3->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+
+ if (flow3->flow_sport)
+ encapnetmask.sen_sport = 0xffff;
+
+ if (flow->flow_dport)
+ encapnetmask.sen_dport = 0xffff;
+ }
+
+ /* Try to add the old entry back in */
+ rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) &encapgw,
+ (struct sockaddr *) &encapnetmask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0);
+
delete_flow(flow, tdbp);
if (flow2)
delete_flow(flow2, tdbp);
@@ -596,6 +631,7 @@ va_dcl
if (error)
{
+ /* Delete the first entry inserted */
encapdst.sen_ip_src.s_addr = emp->em_ena_isrc.s_addr;
encapnetmask.sen_ip_src.s_addr = emp->em_ena_ismask.s_addr;
@@ -604,12 +640,65 @@ va_dcl
(struct sockaddr *) &encapnetmask, 0,
(struct rtentry **) 0);
+ /* Setup the old entries */
+ encapdst.sen_len = SENT_IP4_LEN;
+ encapdst.sen_family = AF_ENCAP;
+ encapdst.sen_type = SENT_IP4;
+ encapdst.sen_ip_src.s_addr = flow3->flow_src.s_addr;
+ encapdst.sen_ip_dst.s_addr = flow3->flow_dst.s_addr;
+ encapdst.sen_proto = flow3->flow_proto;
+ encapdst.sen_sport = flow3->flow_sport;
+ encapdst.sen_dport = flow3->flow_dport;
+
+ encapgw.sen_len = SENT_IPSP_LEN;
+ encapgw.sen_family = AF_ENCAP;
+ encapgw.sen_type = SENT_IPSP;
+ encapgw.sen_ipsp_dst.s_addr = flow3->flow_sa->tdb_dst.s_addr;
+ encapgw.sen_ipsp_spi = flow3->flow_sa->tdb_spi;
+ encapgw.sen_ipsp_sproto = flow3->flow_sa->tdb_sproto;
+
+ encapnetmask.sen_len = SENT_IP4_LEN;
+ encapnetmask.sen_family = AF_ENCAP;
+ encapnetmask.sen_type = SENT_IP4;
+ encapnetmask.sen_ip_src.s_addr = flow3->flow_srcmask.s_addr;
+ encapnetmask.sen_ip_dst.s_addr = flow3->flow_dstmask.s_addr;
+
+ if (flow3->flow_proto)
+ {
+ encapnetmask.sen_proto = 0xff;
+
+ if (flow3->flow_sport)
+ encapnetmask.sen_sport = 0xffff;
+
+ if (flow->flow_dport)
+ encapnetmask.sen_dport = 0xffff;
+ }
+
+ rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) &encapgw,
+ (struct sockaddr *) &encapnetmask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0);
+
+ encapdst.sen_ip_src.s_addr = INADDR_ANY;
+ encapnetmask.sen_ip_src.s_addr = INADDR_BROADCAST;
+
+ rtrequest(RTM_ADD, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) &encapgw,
+ (struct sockaddr *) &encapnetmask,
+ RTF_UP | RTF_GATEWAY | RTF_STATIC,
+ (struct rtentry **) 0);
+
delete_flow(flow, tdbp);
delete_flow(flow2, tdbp);
SENDERR(error);
}
}
+ /*
+ * If we're here, it means we've successfully added the new
+ * entries, so free the old ones.
+ */
if (flow3)
delete_flow(flow3, flow3->flow_sa);
@@ -624,7 +713,8 @@ va_dcl
if (emlen != EMT_DISABLESPI_FLEN)
SENDERR(EINVAL);
- tdbp = gettdb(emp->em_ena_spi, emp->em_ena_dst, emp->em_ena_sproto);
+ tdbp = gettdb(emp->em_ena_spi, emp->em_ena_dst,
+ emp->em_ena_sproto);
if (tdbp == NULL)
SENDERR(ENOENT);
@@ -648,6 +738,9 @@ va_dcl
emp->em_ena_sport, emp->em_ena_dport, tdbp);
if (flow2 == (struct flow *) NULL)
SENDERR(ENOENT);
+
+ if (flow == flow2)
+ SENDERR(EINVAL);
}
/* Setup the encap fields */
@@ -678,38 +771,50 @@ va_dcl
}
/* Delete the entry */
- error = rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
- (struct sockaddr *) 0,
- (struct sockaddr *) &encapnetmask, 0,
- (struct rtentry **) 0);
-
- delete_flow(flow, tdbp);
-
- if (error)
- SENDERR(error);
-
+ rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) 0,
+ (struct sockaddr *) &encapnetmask, 0,
+ (struct rtentry **) 0);
+
if (emp->em_ena_flags & ENABLE_FLAG_LOCAL)
{
encapdst.sen_ip_src.s_addr = INADDR_ANY;
encapnetmask.sen_ip_src.s_addr = INADDR_BROADCAST;
- error = rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
- (struct sockaddr *) 0,
- (struct sockaddr *) &encapnetmask, 0,
- (struct rtentry **) 0);
-
+ rtrequest(RTM_DELETE, (struct sockaddr *) &encapdst,
+ (struct sockaddr *) 0,
+ (struct sockaddr *) &encapnetmask, 0,
+ (struct rtentry **) 0);
+
delete_flow(flow2, tdbp);
-
- if (error)
- SENDERR(error);
}
+ delete_flow(flow, tdbp);
+
break;
+ case EMT_REPLACESPI:
+ if (emlen <= EMT_REPLACESPI_FLEN)
+ SENDERR(EINVAL);
+
+ /* XXX Not yet finished */
+
+ SENDERR(EINVAL);
+
+ break;
+
case EMT_NOTIFY:
if (emlen <= EMT_NOTIFY_FLEN)
SENDERR(EINVAL);
+
+ if (emp->em_not_type != NOTIFY_REQUEST_SA)
+ SENDERR(EINVAL);
+
+ tdbp = gettdb(emp->em_not_spi, emp->em_not_dst,
+ emp->em_not_sproto);
+ if (tdbp == NULL)
+ SENDERR(ENOENT);
/* XXX Not yet finished */
@@ -721,11 +826,6 @@ va_dcl
SENDERR(EINVAL);
}
- if (buffer)
- free(buffer, M_TEMP);
-
- return error;
-
flush:
if (m)
m_freem(m);
@@ -736,6 +836,56 @@ flush:
return error;
}
+void
+encap_sendnotify(int subtype, struct tdb *tdbp)
+{
+ struct encap_msghdr em;
+ struct mbuf *m;
+
+ bzero(&em, sizeof(struct encap_msghdr));
+
+ em.em_msglen = EMT_NOTIFY_FLEN;
+ em.em_version = PFENCAP_VERSION_1;
+ em.em_type = EMT_NOTIFY;
+
+ notify_msgids++;
+
+ switch (subtype)
+ {
+ case NOTIFY_SOFT_EXPIRE:
+ case NOTIFY_HARD_EXPIRE:
+ em.em_not_spi = tdbp->tdb_spi;
+ em.em_not_sproto = tdbp->tdb_sproto;
+ em.em_not_dst.s_addr = tdbp->tdb_dst.s_addr;
+ em.em_not_type = subtype;
+ em.em_not_satype = tdbp->tdb_satype;
+ break;
+
+ case NOTIFY_REQUEST_SA:
+ /* XXX */
+ return;
+
+ default:
+#ifdef ENCDEBUG
+ if (encdebug)
+ log(LOG_WARN, "encap_sendnotify(): unknown subtype %d", subtype);
+#endif /* ENCDEBUG */
+ return;
+ }
+
+ m = m_gethdr(M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ {
+ log(LOG_ERR, "encap_sendnotify(): m_gethdr() returned NULL");
+ return;
+ }
+
+ m_copyback(m, 0, em.em_msglen, (caddr_t) &em);
+ raw_input(m, &encap_proto, &encap_src, &encap_dst);
+
+ return;
+}
+
struct ifaddr *
encap_findgwifa(struct sockaddr *gw)
{
diff --git a/sys/net/encap.h b/sys/net/encap.h
index 8ee2cec21dd..4672ba0a2a3 100644
--- a/sys/net/encap.h
+++ b/sys/net/encap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: encap.h,v 1.9 1997/07/15 23:11:09 provos Exp $ */
+/* $OpenBSD: encap.h,v 1.10 1997/07/27 23:30:32 niklas Exp $ */
/*
* The author of this code is John Ioannidis, ji@tla.org,
@@ -153,8 +153,6 @@ struct encap_msghdr
* (is zero). */
struct in_addr oSrc; /* Outter header source address */
struct in_addr oDst; /* Same, for destination address */
- u_int64_t Relative_Hard; /* Expire relative to creation */
- u_int64_t Relative_Soft;
u_int64_t First_Use_Hard; /* Expire relative to first use */
u_int64_t First_Use_Soft;
u_int64_t Expire_Hard; /* Expire at fixed point in time */
@@ -170,39 +168,35 @@ struct encap_msghdr
* the system default TTL will be used.
* If set to anything else, then the
* ttl used will be TTL % 256 */
+ u_int16_t Satype;
u_int8_t Sproto; /* ESP or AH */
- u_int8_t Foo[3]; /* Alignment */
+ u_int8_t Foo; /* Alignment */
u_int8_t Dat[1]; /* Data */
} Xfm;
/*
* For expiration notifications, the kernel fills in
- * Notification_Type, Spi, Dst and Sproto.
+ * Notification_Type, Spi, Dst and Sproto, Src and Satype.
* No direct response is expected.
*
* For SA Requests, the kernel fills in
- * Notification_Type, MsgID, Seclevel, Dst, SAType, (and optionally
+ * Notification_Type, MsgID, Dst, Satype, (and optionally
* Protocol, Src, Sport, Dport and UserID).
*
- * The response should have the same values in all the fields
- * and:
- * Spi will hold the SPI for the three seclevels
- * Sproto will hold the IPsec protocol used (AH/ESP)
- * UserID can optionally hold the peer's UserID (if applicable)
*/
struct /* kernel->userland notifications */
{
u_int32_t Notification_Type;
u_int32_t MsgID; /* Request ID */
u_int32_t Spi;
- u_int32_t SAType; /* What do we want for this SA */
struct in_addr Dst; /* Peer */
struct in_addr Src; /* Might have our local address */
u_int16_t Sport; /* Source port */
u_int16_t Dport; /* Destination port */
u_int8_t Protocol; /* Transport protocol */
u_int8_t Sproto; /* IPsec protocol */
- u_int8_t Foo[2]; /* Alignment */
+ u_int16_t Satype; /* SA type */
+ u_int32_t Foo; /* Alignment */
u_int8_t UserID[1]; /* Might be used to indicate user */
} Notify;
@@ -215,7 +209,6 @@ struct encap_msghdr
struct in_addr Dst2;
u_int8_t Sproto; /* IPsec protocol */
u_int8_t Sproto2;
- u_int16_t Foo;
} Rel;
/* Enable/disable an SA for a session */
@@ -232,6 +225,9 @@ struct encap_msghdr
u_int8_t Protocol; /* Transport mode for which protocol */
u_int8_t Sproto; /* IPsec protocol */
u_int16_t Flags;
+ u_int32_t Spi2; /* Used in REPLACESPI... */
+ struct in_addr Dst2; /* ...to specify which SPI is... */
+ u_int8_t Sproto2; /* ...replaced. */
} Ena;
/* For general use: (in)validate, delete (chain), reserve */
@@ -240,7 +236,6 @@ struct encap_msghdr
u_int32_t Spi;
struct in_addr Dst;
u_int8_t Sproto;
- u_int8_t Foo[3];
} Gen;
} Eu;
};
@@ -277,7 +272,7 @@ struct encap_msghdr
#define em_not_type Eu.Notify.Notification_Type
#define em_not_spi Eu.Notify.Spi
#define em_not_dst Eu.Notify.Dst
-#define em_not_satype Eu.Notify.SAType
+#define em_not_satype Eu.Notify.Satype
#define em_not_userid Eu.Notify.UserID
#define em_not_msgid Eu.Notify.MsgID
#define em_not_sport Eu.Notify.Sport
@@ -292,8 +287,6 @@ struct encap_msghdr
#define em_odst Eu.Xfm.oDst
#define em_alg Eu.Xfm.Alg
#define em_dat Eu.Xfm.Dat
-#define em_relative_hard Eu.Xfm.Relative_Hard
-#define em_relative_soft Eu.Xfm.Relative_Soft
#define em_first_use_hard Eu.Xfm.First_Use_Hard
#define em_first_use_soft Eu.Xfm.First_Use_Soft
#define em_expire_hard Eu.Xfm.Expire_Hard
@@ -304,6 +297,7 @@ struct encap_msghdr
#define em_packets_soft Eu.Xfm.Packets_Soft
#define em_ttl Eu.Xfm.TTL
#define em_sproto Eu.Xfm.Sproto
+#define em_satype Eu.Xfm.Satype
#define em_rel_spi Eu.Rel.Spi
#define em_rel_spi2 Eu.Rel.Spi2
@@ -320,21 +314,19 @@ struct encap_msghdr
#define EMT_ENABLESPI 6 /* Enable an SA */
#define EMT_DISABLESPI 7 /* Disable an SA */
#define EMT_NOTIFY 8 /* kernel->userland key mgmt not. */
-#define EMT_VALIDATE 9 /* Make an SPI valid for use */
-#define EMT_INVALIDATE 10 /* Make an SPI invalid for use */
+#define EMT_REPLACESPI 10 /* Replace all uses of an SA */
/* Total packet lengths */
-#define EMT_SETSPI_FLEN 120
-#define EMT_GRPSPIS_FLEN 28
-#define EMT_GENLEN 20
+#define EMT_SETSPI_FLEN 104
+#define EMT_GRPSPIS_FLEN 26
+#define EMT_GENLEN 17
#define EMT_DELSPI_FLEN EMT_GENLEN
#define EMT_DELSPICHAIN_FLEN EMT_GENLEN
#define EMT_RESERVESPI_FLEN EMT_GENLEN
-#define EMT_VALIDATE_FLEN EMT_GENLEN
-#define EMT_INVALIDATE_FLEN EMT_GENLEN
#define EMT_NOTIFY_FLEN 40
-#define EMT_ENABLESPI_FLEN 40
+#define EMT_ENABLESPI_FLEN 49
#define EMT_DISABLESPI_FLEN EMT_ENABLESPI_FLEN
+#define EMT_REPLACESPI_FLEN EMT_ENABLESPI_FLEN
#ifdef _KERNEL
extern struct ifaddr *encap_findgwifa(struct sockaddr *);
diff --git a/sys/net/route.c b/sys/net/route.c
index 05ef2994fa7..daaebc86673 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.3 1997/02/20 01:07:43 deraadt Exp $ */
+/* $OpenBSD: route.c,v 1.4 1997/07/27 23:30:33 niklas Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -356,7 +356,7 @@ rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
#define senderr(x) { error = x ; goto bad; }
if ((rnh = rt_tables[dst->sa_family]) == 0)
- senderr(ESRCH);
+ senderr(EAFNOSUPPORT);
if (flags & RTF_HOST)
netmask = 0;
switch (req) {
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)