summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-09 03:46:04 +0000
committerAngelos D. Keromytis <angelos@cvs.openbsd.org>1999-12-09 03:46:04 +0000
commit48397092233d0a7912d0d320ddc2e5183d89c313 (patch)
tree4702714a4dc3e51e2b134f90c4bc86fb66eb2000
parentf636c31445ce47e42482681a6e56146a86d9fe84 (diff)
IPv6 support should now be complete (well, we need the right hooks in
ip6_input())
-rw-r--r--sys/netinet/ip_esp.c380
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 */