diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-25 04:48:17 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-25 04:48:17 +0000 |
commit | 19d8f442cc18028e750d8eccc0e9b51a134b4193 (patch) | |
tree | 4131d7e40c265102a2f6f5d29e45f75bdfbf4dc1 /sys | |
parent | 4a6ef205c38d6e48720b261c61dd09049cba0f65 (diff) |
Move the IPsec packet-processing loop to a separate routine, so we can
reuse it in ip6_output and the bridge. The policy-lookup code will
probably follow suit in a separate routine sometime soon.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/ip_ipsp.c | 247 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 6 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 159 |
3 files changed, 268 insertions, 144 deletions
diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 9ba1f87556e..8f6b4a6bcc7 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.59 1999/12/08 06:06:43 itojun Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.60 1999/12/25 04:48:16 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -45,27 +45,28 @@ #include <sys/systm.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#include <sys/domain.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/errno.h> -#include <sys/time.h> #include <sys/kernel.h> #include <sys/proc.h> #include <net/if.h> #include <net/route.h> +#ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/in_pcb.h> -#include <netinet/in_var.h> -#include <netinet/ip_var.h> -#include <netinet/ip_icmp.h> +#endif /* INET */ + +#ifdef INET6 +#include <netinet6/in6.h> +#include <netinet6/ip6.h> +#endif /* INET6 */ -#include <net/raw_cb.h> #include <net/pfkeyv2.h> #include <netinet/ip_ipsp.h> @@ -85,6 +86,10 @@ void tdb_hashstats(void); #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + #ifdef __GNUC__ #define INLINE static __inline #endif @@ -1495,3 +1500,231 @@ ipsp_address(union sockaddr_union sa) return "(unknown address family)"; } } + +/* + * Loop over a tdb chain, taking into consideration protocol tunneling. The + * fourth argument is set if the first encapsulation header is already in + * place. + */ +int +ipsp_process_packet(struct mbuf *m, struct mbuf **mp, struct tdb *tdb, int *af, + int tunalready) +{ + int i, error, off; + struct tdb *t; + +#ifdef INET + struct ip *ip; +#endif /* INET */ + +#ifdef INET6 + struct ip6_hdr *ip6; +#endif /* INET6 */ + + for (t = tdb; t != NULL; t = t->tdb_onext) + if ((t->tdb_sproto == IPPROTO_ESP && !esp_enable) || + (t->tdb_sproto == IPPROTO_AH && !ah_enable)) + { + DPRINTF(("ipsp_process_packet(): IPSec outbound packet dropped due to policy\n")); + m_freem(m); + return EHOSTUNREACH; + } + + while (tdb && tdb->tdb_xform) + { + /* Check if the SPI is invalid */ + if (tdb->tdb_flags & TDBF_INVALID) + { + DPRINTF(("ipsp_process_packet(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto)); + m_freem(m); + return ENXIO; + } + +#ifndef INET6 + /* Sanity check */ + if (tdb->tdb_dst.sa.sa_family != AF_INET) + { + DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family)); + m_freem(m); + return ENXIO; + } +#endif /* INET6 */ + +#ifndef INET + /* Sanity check */ + if (tdb->tdb_dst.sa.sa_family != AF_INET6) + { + DPRINTF(("ipsp_process_packet(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family)); + m_freem(m); + return ENXIO; + } +#endif /* INET */ + + /* Register first use, setup expiration timer */ + if (tdb->tdb_first_use == 0) + { + tdb->tdb_first_use = time.tv_sec; + tdb_expiration(tdb, TDBEXP_TIMEOUT); + } + + /* Check for tunneling if we don't have the first header in place */ + if (tunalready == 0) + { + if ((*af) == tdb->tdb_dst.sa.sa_family) + { +#ifdef INET + if ((*af) == AF_INET) + i = sizeof(struct ip); +#endif /* INET */ + +#ifdef INET6 + if ((*af) == AF_INET6) + i = sizeof(struct ip6_hdr); +#endif /* INET6 */ + + if (m->m_len < i) + { + if ((m = m_pullup(m, i)) == 0) + return ENOBUFS; + } + +#ifdef INET + ip = mtod(m, struct ip *); +#endif /* INET */ + +#ifdef INET6 + ip6 = mtod(m, struct ip6_hdr *); +#endif /* INET6 */ + } + + if ((tdb->tdb_dst.sa.sa_family != (*af)) || + ((tdb->tdb_flags & TDBF_TUNNELING) && + (tdb->tdb_xform->xf_type != XF_IP4)) || +#ifdef INET + ((tdb->tdb_dst.sa.sa_family == AF_INET) && + (tdb->tdb_dst.sin.sin_addr.s_addr != INADDR_ANY) && + (tdb->tdb_dst.sin.sin_addr.s_addr != ip->ip_dst.s_addr)) || +#endif /* INET */ +#ifdef INET6 + ((tdb->tdb_dst.sa.sa_family == AF_INET6) && + (!IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr)) && + (!IN6_ARE_ADDR_EQUAL(&tdb->tdb_dst.sin6.sin6_addr, + &ip6->ip6_dst))) || +#endif /* INET6 */ + 0) + { +#ifdef INET + /* Fix IPv4 header checksum and length */ + if ((*af) == AF_INET) + { + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + i = ip->ip_hl << 2; + off = offsetof(struct ip, ip_p); + } +#endif /* INET */ + +#ifdef INET6 + /* Fix IPv6 header payload length */ + if ((*af) == AF_INET6) + { + ip6->ip6_plen = htons(m->m_pkthdr.len); + i = sizeof(struct ip6_hdr); + off = offsetof(struct ip6_hdr, ip6_nxt); + } +#endif /* INET6 */ + + /* Encapsulate */ + error = ipe4_output(m, tdb, mp, i, off); + if ((*mp) == NULL) + error = EFAULT; + if (error) + { + if (*mp) + m_freem(*mp); + return error; + } + + *af = tdb->tdb_dst.sa.sa_family; + m = *mp; + *mp = NULL; + } + } + else + { + tunalready = 0; + + if (tdb->tdb_xform->xf_type == XF_IP4) + continue; + } + +#ifdef INET + if (tdb->tdb_dst.sa.sa_family == AF_INET) + { + ip = mtod(m, struct ip *); + i = ip->ip_hl << 2; + off = offsetof(struct ip, ip_p); + + if (tdb->tdb_xform->xf_type == XF_IP4) + { + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_sum = in_cksum(m, i); + } + } +#endif /* INET */ + +#ifdef INET6 + if (tdb->tdb_dst.sa.sa_family == AF_INET6) + { + ip6 = mtod(m, struct ip6_hdr *); + i = sizeof(struct ip6_hdr); + off = offsetof(struct ip6_hdr, ip6_nxt); + ip6->ip6_plen = htons(m->m_pkthdr.len); + } +#endif /* INET6 */ + + error = (*(tdb->tdb_xform->xf_output))(m, tdb, mp, i, off); + if ((*mp) == NULL) + error = EFAULT; + if (error) + { + if (*mp) + m_freem(*mp); + return error; + } + + m = *mp; + *mp = NULL; + tdb = tdb->tdb_onext; + +#ifdef INET + /* Fix the header length, for AH processing */ + if ((*af) == AF_INET) + { + ip = mtod(m, struct ip *); + ip->ip_len = htons(m->m_pkthdr.len); + } +#endif /* INET */ + +#ifdef INET6 + /* Fix the header length, for AH processing */ + if ((*af) == AF_INET6) + { + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(m->m_pkthdr.len); + } +#endif /* INET6 */ + } + +#ifdef INET + /* Fix checksum */ + if ((*af) == AF_INET) + { + ip = mtod(m, struct ip *); + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + } +#endif /* INET */ + + *mp = m; + return 0; +} diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index 0f2a2d8ee19..cf204a90083 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.h,v 1.50 1999/12/08 12:10:25 angelos Exp $ */ +/* $OpenBSD: ip_ipsp.h,v 1.51 1999/12/25 04:48:16 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -563,5 +563,9 @@ extern int checkreplaywindow32(u_int32_t, u_int32_t, u_int32_t *, u_int32_t, u_int32_t *); extern unsigned char ipseczeroes[]; + +/* Packet processing */ +int ipsp_process_packet(struct mbuf *, struct mbuf **, struct tdb *, + int *, int); #endif /* _KERNEL */ #endif /* _NETINET_IPSP_H_ */ diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 678a6ca1c04..691128fe25a 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.59 1999/12/21 08:23:06 angelos Exp $ */ +/* $OpenBSD: ip_output.c,v 1.60 1999/12/25 04:48:16 angelos Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -140,8 +140,8 @@ ip_output(m0, va_alist) struct route_enc re0, *re = &re0; struct sockaddr_encap *ddst, *gw; u_int8_t sa_require, sa_have = 0; - struct tdb *tdb, *t; - int s, ip6flag = 0; + int s, protoflag = AF_INET; + struct tdb *tdb; #ifdef INET6 struct ip6_hdr *ip6; @@ -392,6 +392,7 @@ sendit: goto no_encap; } + /* Do an SPD lookup */ ddst = (struct sockaddr_encap *) &re->re_dst; ddst->sen_family = PF_KEY; ddst->sen_len = SENT_IP4_LEN; @@ -516,8 +517,7 @@ sendit: */ splx(s); goto no_encap; - } - else { + } else { if (tdb->tdb_authalgxform) sa_require = NOTIFY_SATYPE_AUTH; if (tdb->tdb_encalgxform) @@ -552,16 +552,19 @@ sendit: */ SPI_CHAIN_ATTRIB(sa_have, tdb_onext, tdb); - if (sa_require & ~sa_have) + if (sa_require & ~sa_have) { + splx(s); goto no_encap; + } if (tdb == NULL) { splx(s); if (gw->sen_type == SENT_IPSP) - DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto)); + DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto)); + #ifdef INET6 - else - DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet6_ntoa4(gw->sen_ipsp6_dst), ntohl(gw->sen_ipsp6_spi), gw->sen_ipsp6_sproto)); + if (gw->sen_type == SENT_IPSP6) + DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet6_ntoa4(gw->sen_ipsp6_dst), ntohl(gw->sen_ipsp6_spi), gw->sen_ipsp6_sproto)); #endif /* INET6 */ if (re->re_rt) @@ -571,138 +574,22 @@ sendit: goto done; } - for (t = tdb; t != NULL; t = t->tdb_onext) - if ((t->tdb_sproto == IPPROTO_ESP && !esp_enable) || - (t->tdb_sproto == IPPROTO_AH && !ah_enable)) { - DPRINTF(("ip_output(): IPSec outbound packet dropped due to policy\n")); - + error = ipsp_process_packet(m, &mp, tdb, &protoflag, 0); + if ((mp == NULL) && (!error)) + error = ENOBUFS; + if (error) { if (re->re_rt) RTFREE(re->re_rt); - error = EHOSTUNREACH; - m_freem(m); + if (mp) + m_freem(mp); goto done; - } - - while (tdb && tdb->tdb_xform) { - /* Check if the SPI is invalid */ - if (tdb->tdb_flags & TDBF_INVALID) { - splx(s); - DPRINTF(("ip_output(): attempt to use invalid SA %s/%08x/%u\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto)); - m_freem(m); - if (re->re_rt) - RTFREE(re->re_rt); - return ENXIO; - } - -#ifndef INET6 - /* Sanity check */ - if (tdb->tdb_dst.sa.sa_family != AF_INET) { - splx(s); - DPRINTF(("ip_output(): attempt to use SA %s/%08x/%u for protocol family %d\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi), tdb->tdb_sproto, tdb->tdb_dst.sa.sa_family)); - m_freem(m); - if (re->re_rt) - RTFREE(re->re_rt); - return ENXIO; - } -#endif /* INET6 */ - - /* Register first use, setup expiration timer */ - if (tdb->tdb_first_use == 0) { - tdb->tdb_first_use = time.tv_sec; - tdb_expiration(tdb, TDBEXP_TIMEOUT); - } - - /* Check for tunneling */ - if (((tdb->tdb_dst.sa.sa_family == AF_INET) && - (tdb->tdb_dst.sin.sin_addr.s_addr != - INADDR_ANY) && - (tdb->tdb_dst.sin.sin_addr.s_addr != - ip->ip_dst.s_addr)) || - (tdb->tdb_dst.sa.sa_family == AF_INET6) || - ((tdb->tdb_flags & TDBF_TUNNELING) && - (tdb->tdb_xform->xf_type != XF_IP4))) { - /* Fix length and checksum */ - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); - error = ipe4_output(m, tdb, &mp, - ip->ip_hl << 2, - offsetof(struct ip, ip_p)); - if (mp == NULL) - error = EFAULT; - if (error) { - splx(s); - if (re->re_rt) - RTFREE(re->re_rt); - return error; - } - if (tdb->tdb_dst.sa.sa_family == AF_INET) - ip6flag = 0; -#ifdef INET6 - if (tdb->tdb_dst.sa.sa_family == AF_INET6) - ip6flag = 1; -#endif /* INET6 */ - m = mp; - mp = NULL; - } - - if ((tdb->tdb_xform->xf_type == XF_IP4) && - (tdb->tdb_dst.sa.sa_family == AF_INET)) { - ip = mtod(m, struct ip *); - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); - } - -#ifdef INET6 - if ((tdb->tdb_xform->xf_type == XF_IP4) && - (tdb->tdb_dst.sa.sa_family == AF_INET6)) { - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(m->m_pkthdr.len); - } -#endif /* INET6 */ - -#ifdef INET6 - /* - * This assumes that there is only just an IPv6 - * header prepended. - */ - if (ip6flag) - error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp, sizeof(struct ip6_hdr), offsetof(struct ip6_hdr, ip6_nxt)); -#endif /* INET6 */ - - if (!ip6flag) - error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp, ip->ip_hl << 2, offsetof(struct ip, ip_p)); - if (!error && mp == NULL) - error = EFAULT; - if (error) { - splx(s); - if (mp != NULL) - m_freem(mp); - if (re->re_rt) - RTFREE(re->re_rt); - return error; - } - - m = mp; - mp = NULL; + } - if (!ip6flag) { - ip = mtod(m, struct ip *); - ip->ip_len = htons(m->m_pkthdr.len); - } + m = mp; + mp = NULL; -#ifdef INET6 - if (ip6flag) { - ip6 = mtod(m, struct ip6_hdr *); - ip6->ip6_plen = htons(m->m_pkthdr.len); - } -#endif /* INET6 */ - tdb = tdb->tdb_onext; - } splx(s); - if (!ip6flag) - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); - /* * At this point, m is pointing to an mbuf chain with the * processed packet. Call ourselves recursively, but @@ -711,7 +598,7 @@ sendit: if (re->re_rt) RTFREE(re->re_rt); - if (!ip6flag) { + if (protoflag == AF_INET) { ip = mtod(m, struct ip *); NTOHS(ip->ip_len); NTOHS(ip->ip_off); @@ -722,7 +609,7 @@ sendit: } #ifdef INET6 - if (ip6flag) { + if (protoflag == AF_INET6) { ip6 = mtod(m, struct ip6_hdr *); NTOHS(ip6->ip6_plen); |