summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2007-02-08 15:25:31 +0000
committerJun-ichiro itojun Hagino <itojun@cvs.openbsd.org>2007-02-08 15:25:31 +0000
commit0a289dde6d7a0ac669dbd63759e45050b4113552 (patch)
treec9292255327902271e8501ccb3fe895d00cce4a3
parent84d3708bda21c7bfce2c56744285d7ed3afeec9a (diff)
- AH: when computing crypto checksum for output, massage source-routing
header. - ipsec_input: fix mistake in IPv6 next-header chasing. - ipsec_output: look for the position to insert AH more carefully. - ip6_output: enable use of AH with extension headers. avoid tunnellinng when source-routing header is present. ok by deraad, naddy, hshoexer
-rw-r--r--sys/netinet/ip_ah.c68
-rw-r--r--sys/netinet/ipsec_input.c23
-rw-r--r--sys/netinet/ipsec_output.c63
-rw-r--r--sys/netinet6/ip6_output.c19
4 files changed, 140 insertions, 33 deletions
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c
index 88e5f09e09c..85d8fd0c245 100644
--- a/sys/netinet/ip_ah.c
+++ b/sys/netinet/ip_ah.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ah.c,v 1.87 2006/12/15 09:32:30 otto Exp $ */
+/* $OpenBSD: ip_ah.c,v 1.88 2007/02/08 15:25:30 itojun Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -206,7 +206,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
#ifdef INET6
struct ip6_ext *ip6e;
struct ip6_hdr ip6;
- int alloc, len, ad;
+ int ad, alloc, nxt;
#endif /* INET6 */
switch (proto) {
@@ -401,28 +401,28 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
} else
break;
- off = ip6.ip6_nxt & 0xff; /* Next header type. */
+ nxt = ip6.ip6_nxt & 0xff; /* Next header type. */
- for (len = 0; len < skip - sizeof(struct ip6_hdr);)
- switch (off) {
+ for (off = 0; off < skip - sizeof(struct ip6_hdr);) {
+ switch (nxt) {
case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
- ip6e = (struct ip6_ext *) (ptr + len);
+ ip6e = (struct ip6_ext *) (ptr + off);
/*
* Process the mutable/immutable
* options -- borrows heavily from the
* KAME code.
*/
- for (count = len + sizeof(struct ip6_ext);
- count < len + ((ip6e->ip6e_len + 1) << 3);) {
+ for (count = off + sizeof(struct ip6_ext);
+ count < off + ((ip6e->ip6e_len + 1) << 3);) {
if (ptr[count] == IP6OPT_PAD1) {
count++;
continue; /* Skip padding. */
}
/* Sanity check. */
- if (count > len +
+ if (count > off +
((ip6e->ip6e_len + 1) << 3)) {
ahstat.ahs_hdrops++;
m_freem(m);
@@ -456,8 +456,8 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
}
/* Advance. */
- len += ((ip6e->ip6e_len + 1) << 3);
- off = ip6e->ip6e_nxt;
+ off += ((ip6e->ip6e_len + 1) << 3);
+ nxt = ip6e->ip6e_nxt;
break;
case IPPROTO_ROUTING:
@@ -465,10 +465,49 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
* Always include routing headers in
* computation.
*/
- ip6e = (struct ip6_ext *) (ptr + len);
- len += ((ip6e->ip6e_len + 1) << 3);
- off = ip6e->ip6e_nxt;
+ {
+ struct ip6_rthdr *rh;
+
+ ip6e = (struct ip6_ext *) (ptr + off);
+ rh = (struct ip6_rthdr *)(ptr + off);
+ /*
+ * must adjust content to make it look like
+ * its final form (as seen at the final
+ * destination).
+ * we only know how to massage type 0 routing
+ * header.
+ */
+ if (out && rh->ip6r_type == IPV6_RTHDR_TYPE_0) {
+ struct ip6_rthdr0 *rh0;
+ struct in6_addr *addr, finaldst;
+ int i;
+
+ rh0 = (struct ip6_rthdr0 *)rh;
+ addr = (struct in6_addr *)(rh0 + 1);
+
+ for (i = 0; i < rh0->ip6r0_segleft; i++)
+ if (IN6_IS_SCOPE_EMBED(&addr[i]))
+ addr[i].s6_addr16[1] = 0;
+
+ finaldst = addr[rh0->ip6r0_segleft - 1];
+ ovbcopy(&addr[0], &addr[1],
+ sizeof(struct in6_addr) *
+ (rh0->ip6r0_segleft - 1));
+
+ m_copydata(m, 0, sizeof(ip6),
+ (caddr_t)&ip6);
+ addr[0] = ip6.ip6_dst;
+ ip6.ip6_dst = finaldst;
+ m_copyback(m, 0, sizeof(ip6), &ip6);
+
+ rh0->ip6r0_segleft = 0;
+ }
+
+ /* advance */
+ off += ((ip6e->ip6e_len + 1) << 3);
+ nxt = ip6e->ip6e_nxt;
break;
+ }
default:
DPRINTF(("ah_massage_headers(): unexpected "
@@ -479,6 +518,7 @@ ah_massage_headers(struct mbuf **m0, int proto, int skip, int alg, int out)
m_freem(m);
return EINVAL;
}
+ }
/* Copyback and free, if we allocated. */
if (alloc) {
diff --git a/sys/netinet/ipsec_input.c b/sys/netinet/ipsec_input.c
index a9a5bc6a630..c3c45b5373b 100644
--- a/sys/netinet/ipsec_input.c
+++ b/sys/netinet/ipsec_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipsec_input.c,v 1.82 2006/12/15 09:32:30 otto Exp $ */
+/* $OpenBSD: ipsec_input.c,v 1.83 2007/02/08 15:25:30 itojun Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -953,7 +953,7 @@ int
ah6_input(struct mbuf **mp, int *offp, int proto)
{
int l = 0;
- int protoff;
+ int protoff, nxt;
struct ip6_ext ip6e;
if (*offp < sizeof(struct ip6_hdr)) {
@@ -964,13 +964,14 @@ ah6_input(struct mbuf **mp, int *offp, int proto)
} else {
/* Chase down the header chain... */
protoff = sizeof(struct ip6_hdr);
+ nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
do {
protoff += l;
m_copydata(*mp, protoff, sizeof(ip6e),
(caddr_t) &ip6e);
- if (ip6e.ip6e_nxt == IPPROTO_AH)
+ if (nxt == IPPROTO_AH)
l = (ip6e.ip6e_len + 2) << 2;
else
l = (ip6e.ip6e_len + 1) << 3;
@@ -978,6 +979,8 @@ ah6_input(struct mbuf **mp, int *offp, int proto)
if (l <= 0)
panic("ah6_input: l went zero or negative");
#endif
+
+ nxt = ip6e.ip6e_nxt;
} while (protoff + l < *offp);
/* Malformed packet check */
@@ -1039,7 +1042,7 @@ int
esp6_input(struct mbuf **mp, int *offp, int proto)
{
int l = 0;
- int protoff;
+ int protoff, nxt;
struct ip6_ext ip6e;
if (*offp < sizeof(struct ip6_hdr)) {
@@ -1050,13 +1053,14 @@ esp6_input(struct mbuf **mp, int *offp, int proto)
} else {
/* Chase down the header chain... */
protoff = sizeof(struct ip6_hdr);
+ nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
do {
protoff += l;
m_copydata(*mp, protoff, sizeof(ip6e),
(caddr_t) &ip6e);
- if (ip6e.ip6e_nxt == IPPROTO_AH)
+ if (nxt == IPPROTO_AH)
l = (ip6e.ip6e_len + 2) << 2;
else
l = (ip6e.ip6e_len + 1) << 3;
@@ -1064,6 +1068,8 @@ esp6_input(struct mbuf **mp, int *offp, int proto)
if (l <= 0)
panic("esp6_input: l went zero or negative");
#endif
+
+ nxt = ip6e.ip6e_nxt;
} while (protoff + l < *offp);
/* Malformed packet check */
@@ -1093,7 +1099,7 @@ int
ipcomp6_input(struct mbuf **mp, int *offp, int proto)
{
int l = 0;
- int protoff;
+ int protoff, nxt;
struct ip6_ext ip6e;
if (*offp < sizeof(struct ip6_hdr)) {
@@ -1104,12 +1110,13 @@ ipcomp6_input(struct mbuf **mp, int *offp, int proto)
} else {
/* Chase down the header chain... */
protoff = sizeof(struct ip6_hdr);
+ nxt = (mtod(*mp, struct ip6_hdr *))->ip6_nxt;
do {
protoff += l;
m_copydata(*mp, protoff, sizeof(ip6e),
(caddr_t) &ip6e);
- if (ip6e.ip6e_nxt == IPPROTO_AH)
+ if (nxt == IPPROTO_AH)
l = (ip6e.ip6e_len + 2) << 2;
else
l = (ip6e.ip6e_len + 1) << 3;
@@ -1117,6 +1124,8 @@ ipcomp6_input(struct mbuf **mp, int *offp, int proto)
if (l <= 0)
panic("ipcomp6_input: l went zero or negative");
#endif
+
+ nxt = ip6e.ip6e_nxt;
} while (protoff + l < *offp);
/* Malformed packet check */
diff --git a/sys/netinet/ipsec_output.c b/sys/netinet/ipsec_output.c
index f9848be7040..2a9d6da4519 100644
--- a/sys/netinet/ipsec_output.c
+++ b/sys/netinet/ipsec_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipsec_output.c,v 1.36 2006/12/19 11:31:10 itojun Exp $ */
+/* $OpenBSD: ipsec_output.c,v 1.37 2007/02/08 15:25:30 itojun Exp $ */
/*
* The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu)
*
@@ -77,6 +77,11 @@ ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
struct timeval tv;
int i, off, error;
struct mbuf *mp;
+#ifdef INET6
+ struct ip6_ext ip6e;
+ int nxt;
+ int dstopt = 0;
+#endif
#ifdef INET
int setdf = 0;
@@ -303,6 +308,62 @@ ipsp_process_packet(struct mbuf *m, struct tdb *tdb, int af, int tunalready)
ip6 = mtod(m, struct ip6_hdr *);
i = sizeof(struct ip6_hdr);
off = offsetof(struct ip6_hdr, ip6_nxt);
+ nxt = ip6->ip6_nxt;
+ /*
+ * chase mbuf chain to find the appropriate place to
+ * put AH/ESP/IPcomp header.
+ * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
+ */
+ do {
+ switch (nxt) {
+ case IPPROTO_AH:
+ case IPPROTO_ESP:
+ case IPPROTO_IPCOMP:
+ /*
+ * we should not skip security header added
+ * beforehand.
+ */
+ goto exitip6loop;
+
+ case IPPROTO_HOPOPTS:
+ case IPPROTO_DSTOPTS:
+ case IPPROTO_ROUTING:
+ /*
+ * if we see 2nd destination option header,
+ * we should stop there.
+ */
+ if (nxt == IPPROTO_DSTOPTS && dstopt)
+ goto exitip6loop;
+
+ if (nxt == IPPROTO_DSTOPTS) {
+ /*
+ * seen 1st or 2nd destination option.
+ * next time we see one, it must be 2nd.
+ */
+ dstopt = 1;
+ } else if (nxt == IPPROTO_ROUTING) {
+ /*
+ * if we see destionation option next
+ * time, it must be dest2.
+ */
+ dstopt = 2;
+ }
+
+ /* skip this header */
+ m_copydata(m, i, sizeof(ip6e), (caddr_t)&ip6e);
+ nxt = ip6e.ip6e_nxt;
+ off = i + offsetof(struct ip6_ext, ip6e_nxt);
+ /*
+ * we will never see nxt == IPPROTO_AH
+ * so it is safe to omit AH case.
+ */
+ i += (ip6e.ip6e_len + 1) << 3;
+ break;
+ default:
+ goto exitip6loop;
+ }
+ } while (i < m->m_pkthdr.len);
+ exitip6loop:;
break;
#endif /* INET6 */
}
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index ceae275e097..04152b61c1b 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.97 2006/12/10 10:16:12 miod Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.98 2007/02/08 15:25:30 itojun Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -288,15 +288,6 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
sspi = tdb->tdb_spi;
sproto = tdb->tdb_sproto;
splx(s);
-
-#if 1 /* XXX */
- /* if we have any extension header, we cannot perform IPsec */
- if (exthdrs.ip6e_hbh || exthdrs.ip6e_dest1 ||
- exthdrs.ip6e_rthdr || exthdrs.ip6e_dest2) {
- error = EHOSTUNREACH;
- goto freehdrs;
- }
-#endif
}
/* Fall through to the routing/multicast handling code */
@@ -521,7 +512,13 @@ ip6_output(m0, opt, ro, flags, im6o, ifpp)
m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
/* Callee frees mbuf */
- error = ipsp_process_packet(m, tdb, AF_INET6, 0);
+ /*
+ * if we are source-routing, do not attempt to tunnel the
+ * packet just because ip6_dst is different from what tdb has.
+ * XXX
+ */
+ error = ipsp_process_packet(m, tdb, AF_INET6,
+ exthdrs.ip6e_rthdr ? 1 : 0);
splx(s);
return error; /* Nothing more to be done */