diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2007-02-08 15:25:31 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2007-02-08 15:25:31 +0000 |
commit | 0a289dde6d7a0ac669dbd63759e45050b4113552 (patch) | |
tree | c9292255327902271e8501ccb3fe895d00cce4a3 | |
parent | 84d3708bda21c7bfce2c56744285d7ed3afeec9a (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.c | 68 | ||||
-rw-r--r-- | sys/netinet/ipsec_input.c | 23 | ||||
-rw-r--r-- | sys/netinet/ipsec_output.c | 63 | ||||
-rw-r--r-- | sys/netinet6/ip6_output.c | 19 |
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 */ |