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 | |
parent | be30223d21a88e015111990b2ce8654b471005ba (diff) |
expiration messages, fixes, updates, all sorts of things
-rw-r--r-- | sys/net/encap.c | 320 | ||||
-rw-r--r-- | sys/net/encap.h | 44 | ||||
-rw-r--r-- | sys/net/route.c | 4 | ||||
-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 |
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) |