diff options
author | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-09 03:46:04 +0000 |
---|---|---|
committer | Angelos D. Keromytis <angelos@cvs.openbsd.org> | 1999-12-09 03:46:04 +0000 |
commit | 48397092233d0a7912d0d320ddc2e5183d89c313 (patch) | |
tree | 4702714a4dc3e51e2b134f90c4bc86fb66eb2000 | |
parent | f636c31445ce47e42482681a6e56146a86d9fe84 (diff) |
IPv6 support should now be complete (well, we need the right hooks in
ip6_input())
-rw-r--r-- | sys/netinet/ip_esp.c | 380 |
1 files changed, 277 insertions, 103 deletions
diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c index e2ea7211264..bea5f7fb206 100644 --- a/sys/netinet/ip_esp.c +++ b/sys/netinet/ip_esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.c,v 1.28 1999/12/07 08:58:00 angelos Exp $ */ +/* $OpenBSD: ip_esp.c,v 1.29 1999/12/09 03:46:03 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -60,6 +60,11 @@ #include <netinet/in_var.h> #include <netinet/ip_var.h> +#ifdef INET6 +#include <netinet6/in6.h> +#include <netinet6/ip6.h> +#endif/ * INET6 */ + #include <sys/socketvar.h> #include <net/raw_cb.h> @@ -86,29 +91,27 @@ extern struct enc_softc encif[]; int esp_enable = 0; /* - * esp_input gets called when we receive an ESP-protected packet + * esp_common_input() gets called when we receive an ESP-protected packet + * in IPv4 or IPv6. */ -void -#if __STDC__ -esp_input(struct mbuf *m, ...) -#else -esp_input(m, va_alist) - register struct mbuf *m; -#endif +static void +esp_common_input(struct mbuf *m, int skip, int protoff, int af) { - int iphlen; union sockaddr_union sunion; struct ifqueue *ifq = NULL; - struct ip *ipo, ipn; struct tdb *tdbp; u_int32_t spi; + u_int8_t prot; int s; - va_list ap; - - va_start(ap, m); - iphlen = va_arg(ap, int); - va_end(ap); + +#ifdef INET + struct ip *ip, ipn; +#endif /* INET */ + +#ifdef INET6 + struct ip6_hdr *ip6, ip6n; +#endif /* INET6 */ espstat.esps_input++; @@ -119,23 +122,8 @@ esp_input(m, va_alist) return; } - /* - * Make sure that at least the SPI is in the same mbuf - */ - - ipo = mtod(m, struct ip *); - if (m->m_len < iphlen + sizeof(u_int32_t)) - { - if ((m = m_pullup(m, iphlen + sizeof(u_int32_t))) == 0) - { - espstat.esps_hdrops++; - return; - } - - ipo = mtod(m, struct ip *); - } - - spi = *((u_int32_t *) ((caddr_t) ipo + iphlen)); + /* Retrieve the SPI from the ESP header */ + m_copydata(m, skip , sizeof(u_int32_t), (unsigned char *) &spi); /* * Find tunnel control block and (indirectly) call the appropriate @@ -144,14 +132,32 @@ esp_input(m, va_alist) */ bzero(&sunion, sizeof(sunion)); - sunion.sin.sin_family = AF_INET; - sunion.sin.sin_len = sizeof(struct sockaddr_in); - sunion.sin.sin_addr = ipo->ip_dst; + sunion.sin.sin_family = af; + +#ifdef INET + if (af == AF_INET) + { + sunion.sin.sin_len = sizeof(struct sockaddr_in); + m_copydata(m, offsetof(struct ip, ip_dst), sizeof(struct in_addr), + (unsigned char *) &(sunion.sin.sin_addr)); + } +#endif /* INET */ + +#ifdef INET6 + if (af == AF_INET6) + { + sunion.sin6.sin6_len = sizeof(struct sockaddr_in6); + m_copydata(m, offsetof(struct ip6_hdr, ip6_dst), + sizeof(struct in6_addr), + (unsigned char *) &(sunion.sin6.sin6_addr)); + } +#endif /* INET6 */ + s = spltdb(); tdbp = gettdb(spi, &sunion, IPPROTO_ESP); if (tdbp == NULL) { - DPRINTF(("esp_input(): could not find SA for packet from %s to %s, spi %08x\n", inet_ntoa4(ipo->ip_src), ipsp_address(sunion), ntohl(spi))); + DPRINTF(("esp_input(): could not find SA for packet to %s, spi %08x\n", ipsp_address(sunion), ntohl(spi))); m_freem(m); espstat.esps_notdb++; return; @@ -159,7 +165,8 @@ esp_input(m, va_alist) if (tdbp->tdb_flags & TDBF_INVALID) { - DPRINTF(("esp_input(): attempted to use invalid SA %08x, packet from %s to %s\n", ntohl(spi), inet_ntoa4(ipo->ip_src), ipsp_address(sunion))); + DPRINTF(("esp_input(): attempted to use invalid SA %s/%08x\n", + ipsp_address(sunion), ntohl(spi))); m_freem(m); espstat.esps_invalid++; return; @@ -167,7 +174,8 @@ esp_input(m, va_alist) if (tdbp->tdb_xform == NULL) { - DPRINTF(("esp_input(): attempted to use uninitialized SA %08x, packet from %s to %s\n", ntohl(spi), inet_ntoa4(ipo->ip_src), ipsp_address(sunion))); + DPRINTF(("esp_input(): attempted to use uninitialized SA %s/%08x\n", + ipsp_address(sunion), ntohl(spi))); m_freem(m); espstat.esps_noxform++; return; @@ -184,73 +192,188 @@ esp_input(m, va_alist) tdbp->tdb_first_use = time.tv_sec; tdb_expiration(tdbp, TDBEXP_TIMEOUT); } - - ipn = *ipo; - - m = (*(tdbp->tdb_xform->xf_input))(m, tdbp, ipo->ip_hl << 2, - offsetof(struct ip, ip_p)); + m = (*(tdbp->tdb_xform->xf_input))(m, tdbp, skip, protoff); if (m == NULL) { - DPRINTF(("esp_input(): processing failed for ESP packet from %s to %s, spi %08x\n", inet_ntoa4(ipn.ip_src), ipsp_address(sunion), ntohl(spi))); + /* esp_xxx_input() will print a message if necessary */ espstat.esps_badkcr++; return; } - if ((m = m_pullup(m, ipn.ip_hl << 2)) == 0) +#ifdef INET + /* Fix IPv4 header */ + if (af == AF_INET) { - espstat.esps_hdrops++; - return; - } + if ((m = m_pullup(m, skip)) == 0) + { + DPRINTF(("esp_input(): processing failed for SA %s/%08x\n", + ipsp_address(tdbp->tdb_dst), ntohl(spi))); + espstat.esps_hdrops++; + return; + } + + ip = mtod(m, struct ip *); + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_sum = 0; + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + prot = ip->ip_p; + + /* IP-in-IP encapsulation */ + if (prot == IPPROTO_IPIP) + { + /* ipn will now contain the inner IPv4 header */ + m_copydata(m, ip->ip_hl << 2, sizeof(struct ip), (caddr_t) &ipn); + + /* + * Check that the inner source address is the same as + * the proxy address, if available. + */ + if (((tdbp->tdb_proxy.sa.sa_family == AF_INET) && + (tdbp->tdb_proxy.sin.sin_addr.s_addr != INADDR_ANY) && + (ipn.ip_src.s_addr != tdbp->tdb_proxy.sin.sin_addr.s_addr)) || + ((tdbp->tdb_proxy.sa.sa_family != AF_INET6) && + (tdbp->tdb_proxy.sa.sa_family != 0))) + { + DPRINTF(("esp_input(): inner source address %s doesn't correspond to expected proxy source %s, SA %s/%08x\n", inet_ntoa4(ipn.ip_src), ipsp_address(tdbp->tdb_proxy), ipsp_address(tdbp->tdb_dst), ntohl(spi))); + m_free(m); + espstat.esps_hdrops++; + return; + } + } - ipo = mtod(m, struct ip *); - ipo->ip_len = htons(m->m_pkthdr.len); - ipo->ip_sum = 0; - ipo->ip_sum = in_cksum(m, ipo->ip_hl << 2); +#if INET6 + /* IPv6-in-IP encapsulation */ + if (prot == IPPROTO_IPV6) + { + /* ip6n will now contain the inner IPv6 header */ + m_copydata(m, ip->ip_hl << 2, sizeof(struct ip6_hdr), + (caddr_t) &ip6n); + + /* + * Check that the inner source address is the same as + * the proxy address, if available. + */ + if (((tdbp->tdb_proxy.sa.sa_family == AF_INET6) && + !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) && + !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, + &tdbp->tdb_proxy.sin6.sin6_addr)) || + ((tdbp->tdb_proxy.sa.sa_family != AF_INET6) && + (tdbp->tdb_proxy.sa.sa_family != 0))) + { + DPRINTF(("esp_input(): inner source address %s doesn't correspond to expected proxy source %s, SA %s/%08x\n", inet6_ntoa4(ip6n.ip6_src), ipsp_address(tdbp->tdb_proxy), ipsp_address(tdbp->tdb_dst), ntohl(spi))); + m_free(m); + espstat.esps_hdrops++; + return; + } + } +#endif /* INET6 */ - if (ipo->ip_p == IPPROTO_IPIP) /* IP-in-IP encapsulation */ - { - /* ipn will now contain the inner IP header */ - m_copydata(m, ipo->ip_hl << 2, sizeof(struct ip), (caddr_t) &ipn); - - 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)) - { - DPRINTF(("esp_input(): ESP-tunnel with different internal addresses %s->%s (%s->%s), SA %s/%08x\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipn.ip_src), ipsp_address(sunion), ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi))); - m_freem(m); - espstat.esps_hdrops++; - return; - } - - /* - * Check that the inner source address is the same as - * the proxy address, if available. + /* + * Check that the source address is an expected one, if we know what + * it's supposed to be. This avoids source address spoofing. */ - if ((tdbp->tdb_proxy.sin.sin_addr.s_addr != INADDR_ANY) && - (ipn.ip_src.s_addr != tdbp->tdb_proxy.sin.sin_addr.s_addr)) + if (((tdbp->tdb_src.sa.sa_family == AF_INET) && + (tdbp->tdb_src.sin.sin_addr.s_addr != INADDR_ANY) && + (ip->ip_src.s_addr != tdbp->tdb_src.sin.sin_addr.s_addr)) || + ((tdbp->tdb_src.sa.sa_family != AF_INET) && + (tdbp->tdb_src.sa.sa_family != 0))) { - DPRINTF(("esp_input(): inner source address %s doesn't correspond to expected proxy source %s, SA %s/%08x\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(tdbp->tdb_proxy.sin.sin_addr), inet_ntoa4(tdbp->tdb_dst.sin.sin_addr), ntohl(tdbp->tdb_spi))); + DPRINTF(("esp_input(): source address %s doesn't correspond to expected source %s, SA %s/%08x\n", inet_ntoa4(ip->ip_src), ipsp_address(tdbp->tdb_src), ipsp_address(tdbp->tdb_dst), ntohl(spi))); m_free(m); espstat.esps_hdrops++; return; } } +#endif /* INET */ - /* - * Check that the source address is an expected one, if we know what - * it's supposed to be. This avoids source address spoofing. - */ - if ((tdbp->tdb_src.sin.sin_addr.s_addr != INADDR_ANY) && - (ipo->ip_src.s_addr != tdbp->tdb_src.sin.sin_addr.s_addr)) +#ifdef INET6 + /* Fix IPv6 header */ + if (af == INET6) { - DPRINTF(("esp_input(): source address %s doesn't correspond to expected source %s, SA %s/%08x\n", inet_ntoa4(ipo->ip_src), ipsp_address(tdbp->tdb_src), ipsp_address(tdbp->tdb_dst), ntohl(tdbp->tdb_spi))); - m_free(m); - espstat.esps_hdrops++; - return; + if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == 0) + { + DPRINTF(("esp_input(): processing failed for SA %s/%08x\n", + ipsp_address(tdbp->tdb_dst), ntohl(spi))); + espstat.esps_hdrops++; + return; + } + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(m->m_pkthdr.len); + + /* Save protocol */ + m_copydata(m, protoff, 1, (unsigned char *) &prot); + +#ifdef INET + /* IP-in-IP encapsulation */ + if (prot == IPPROTO_IPIP) + { + /* ipn will now contain the inner IPv4 header */ + m_copydata(m, skip, sizeof(struct ip), (caddr_t) &ipn); + + /* + * Check that the inner source address is the same as + * the proxy address, if available. + */ + if (((tdbp->tdb_proxy.sa.sa_family == AF_INET) && + (tdbp->tdb_proxy.sin.sin_addr.s_addr != INADDR_ANY) && + (ipn.ip_src.s_addr != tdbp->tdb_proxy.sin.sin_addr.s_addr)) || + ((tdbp->tdb_proxy.sa.sa_family != AF_INET) && + (tdbp->tdb_proxy.sa.sa_family != 0))) + { + DPRINTF(("esp_input(): inner source address %s doesn't correspond to expected proxy source %s, SA %s/%08x\n", inet_ntoa4(ipn.ip_src), ipsp_address(tdbp->tdb_proxy), ipsp_address(tdbp->tdb_dst), ntohl(spi))); + m_free(m); + espstat.esps_hdrops++; + return; + } + } +#endif /* INET */ + + /* IPv6-in-IP encapsulation */ + if (prot == IPPROTO_IPV6) + { + /* ip6n will now contain the inner IPv6 header */ + m_copydata(m, skip, sizeof(struct ip6_hdr), (caddr_t) &ip6n); + + /* + * Check that the inner source address is the same as + * the proxy address, if available. + */ + if (((tdbp->tdb_proxy.sa.sa_family == AF_INET6) && + !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_proxy.sin6.sin6_addr) && + !IN6_ARE_ADDR_EQUAL(&ip6n.ip6_src, + &tdbp->tdb_proxy.sin6.sin6_addr)) || + ((tdbp->tdb_proxy.sa.sa_family != AF_INET6) && + (tdbp->tdb_proxy.sa.sa_family != 0))) + { + DPRINTF(("esp_input(): inner source address %s doesn't correspond to expected proxy source %s, SA %s/%08x\n", inet6_ntoa4(ip6n.ip6_src), ipsp_address(tdbp->tdb_proxy), ipsp_address(tdbp->tdb_dst), ntohl(spi))); + m_free(m); + espstat.esps_hdrops++; + return; + } + } + + /* + * Check that the source address is an expected one, if we know what + * it's supposed to be. This avoids source address spoofing. + */ + if (((tdbp->tdb_src.sa.sa_family == AF_INET6) && + !IN6_IS_ADDR_UNSPECIFIED(&tdbp->tdb_src.sin6.sin6_addr) && + !IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, + &tdbp->tdb_src.sin6.sin6_addr)) || + ((tdbp->tdb_src.sa.sa_family != AF_INET6) && + (tdbp->tdb_src.sa.sa_family != 0))) + { + DPRINTF(("esp_input(): source address %s doesn't correspond to expected source %s, SA %s/%08x\n", inet6_ntoa4(ip6->ip6_src), ipsp_address(tdbp->tdb_src), ipsp_address(tdbp->tdb_dst), ntohl(spi))); + m_free(m); + espstat.esps_hdrops++; + return; + } } +#endif /* INET6 */ - if (ipo->ip_p == IPPROTO_TCP || ipo->ip_p == IPPROTO_UDP) + if (prot == IPPROTO_TCP || prot == IPPROTO_UDP) { struct tdb_ident *tdbi = NULL; @@ -258,24 +381,23 @@ esp_input(m, va_alist) { tdbi = m->m_pkthdr.tdbi; if (!(m->m_flags & M_PKTHDR)) - { - DPRINTF(("esp_input(): mbuf is not a packet header!\n")); - } + DPRINTF(("esp_input(): mbuf is not a packet header!\n")); + MALLOC(tdbi, struct tdb_ident *, sizeof(struct tdb_ident), M_TEMP, M_NOWAIT); - if (!tdbi) - goto no_mem; - - tdbi->spi = tdbp->tdb_bind_out->tdb_spi; - tdbi->dst = tdbp->tdb_bind_out->tdb_dst; - tdbi->proto = tdbp->tdb_bind_out->tdb_sproto; + if (tdbi == NULL) + m->m_pkthdr.tdbi = NULL; + else + { + tdbi->spi = tdbp->tdb_bind_out->tdb_spi; + tdbi->dst = tdbp->tdb_bind_out->tdb_dst; + tdbi->proto = tdbp->tdb_bind_out->tdb_sproto; + } } - - no_mem: - m->m_pkthdr.tdbi = tdbi; - } else - m->m_pkthdr.tdbi = NULL; + } + else + m->m_pkthdr.tdbi = NULL; /* Packet is confidental */ m->m_flags |= M_CONF; @@ -293,7 +415,7 @@ esp_input(m, va_alist) struct mbuf m0; struct enchdr hdr; - hdr.af = AF_INET; + hdr.af = af; hdr.spi = tdbp->tdb_spi; hdr.flags = m->m_flags & (M_AUTH|M_CONF); @@ -311,14 +433,22 @@ esp_input(m, va_alist) * `outer' header and reschedule. */ - ifq = &ipintrq; +#ifdef INET + if (af == AF_INET) + ifq = &ipintrq; +#endif /* INET */ + +#ifdef INET6 + if (af == AF_INET6) + ifq = &ip6intrq; +#endif /* INET6 */ s = splimp(); /* isn't it already? */ if (IF_QFULL(ifq)) { IF_DROP(ifq); if (m->m_pkthdr.tdbi) - free(m->m_pkthdr.tdbi, M_TEMP); + free(m->m_pkthdr.tdbi, M_TEMP); m_freem(m); espstat.esps_qfull++; splx(s); @@ -327,7 +457,17 @@ esp_input(m, va_alist) } IF_ENQUEUE(ifq, m); - schednetisr(NETISR_IP); + +#ifdef INET + if (af == AF_INET) + schednetisr(NETISR_IP); +#endif /* INET */ + +#ifdef INET6 + if (af == AF_INET6) + schednetisr(NETISR_IPV6); +#endif /* INET6 */ + splx(s); return; } @@ -353,3 +493,37 @@ esp_sysctl(name, namelen, oldp, oldlenp, newp, newlen) } /* NOTREACHED */ } + +#ifdef INET +/* IPv4 ESP wrapper */ +void +esp_input(struct mbuf *m, ...) +{ + int skip; + + va_list ap; + va_start(ap, m); + skip = va_arg(ap, int); + va_end(ap); + + esp_common_input(m, skip, offsetof(struct ip, ip_p), AF_INET); +} +#endif /* INET */ + +#ifdef INET6 +/* IPv6 ESP wrapper */ +void +esp6_input(struct mbuf *m, ...) +{ + int skip, protoff; + + va_list ap; + + va_start(ap, m); + skip = va_arg(ap, int); + protoff = va_arg(ap, int); + va_end(ap); + + esp_common_input(m, skip, protoff, AF_INET6); +} +#endif /* INET6 */ |