Module Name: src Committed By: drochner Date: Tue Jan 10 20:01:57 UTC 2012
Modified Files: src/sys/netinet6: ip6_input.c ip6_output.c ip6_var.h src/sys/netipsec: ipsec_output.c xform_ah.c Log Message: add patch from Arnaud Degroote to handle IPv6 extended options with (FAST_)IPSEC, tested lightly with a DSTOPTS header consisting of PAD1 To generate a diff of this commit: cvs rdiff -u -r1.135 -r1.136 src/sys/netinet6/ip6_input.c cvs rdiff -u -r1.142 -r1.143 src/sys/netinet6/ip6_output.c cvs rdiff -u -r1.56 -r1.57 src/sys/netinet6/ip6_var.h cvs rdiff -u -r1.37 -r1.38 src/sys/netipsec/ipsec_output.c cvs rdiff -u -r1.33 -r1.34 src/sys/netipsec/xform_ah.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet6/ip6_input.c diff -u src/sys/netinet6/ip6_input.c:1.135 src/sys/netinet6/ip6_input.c:1.136 --- src/sys/netinet6/ip6_input.c:1.135 Sat Dec 31 20:41:59 2011 +++ src/sys/netinet6/ip6_input.c Tue Jan 10 20:01:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.135 2011/12/31 20:41:59 christos Exp $ */ +/* $NetBSD: ip6_input.c,v 1.136 2012/01/10 20:01:56 drochner Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.135 2011/12/31 20:41:59 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.136 2012/01/10 20:01:56 drochner Exp $"); #include "opt_gateway.h" #include "opt_inet.h" @@ -161,7 +161,8 @@ percpu_t *ip6stat_percpu; static void ip6_init2(void *); static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *); -static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); +static int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *, + u_int32_t *); static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); static void sysctl_net_inet6_ip6_setup(struct sysctllog **); @@ -882,7 +883,7 @@ ip6_getdstifaddr(struct mbuf *m) * * rtalertp - XXX: should be stored more smart way */ -static int +int ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, struct mbuf **mp, int *offp) { @@ -927,7 +928,7 @@ ip6_hopopts_input(u_int32_t *plenp, u_in * (RFC2460 p7), opthead is pointer into data content in m, and opthead to * opthead + hbhlen is located in continuous memory region. */ -int +static int ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, u_int32_t *rtalertp, u_int32_t *plenp) { Index: src/sys/netinet6/ip6_output.c diff -u src/sys/netinet6/ip6_output.c:1.142 src/sys/netinet6/ip6_output.c:1.143 --- src/sys/netinet6/ip6_output.c:1.142 Sat Dec 31 20:41:59 2011 +++ src/sys/netinet6/ip6_output.c Tue Jan 10 20:01:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_output.c,v 1.142 2011/12/31 20:41:59 christos Exp $ */ +/* $NetBSD: ip6_output.c,v 1.143 2012/01/10 20:01:56 drochner Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.142 2011/12/31 20:41:59 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.143 2012/01/10 20:01:56 drochner Exp $"); #include "opt_inet.h" #include "opt_inet6.h" @@ -317,10 +317,6 @@ ip6_output( #ifdef FAST_IPSEC /* Check the security policy (SP) for the packet */ - /* XXX For moment, we doesn't support packet with extented action */ - if (optlen !=0) - goto freehdrs; - sp = ipsec6_check_policy(m,so,flags,&needipsec,&error); if (error != 0) { /* @@ -858,28 +854,18 @@ skip_ipsec2:; * it must be examined and processed even by the source node. * (RFC 2460, section 4.) */ - if (exthdrs.ip6e_hbh) { - struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *); + if (ip6->ip6_nxt == IPV6_HOPOPTS) { u_int32_t dummy1; /* XXX unused */ u_int32_t dummy2; /* XXX unused */ + int hoff = sizeof(struct ip6_hdr); - /* - * XXX: if we have to send an ICMPv6 error to the sender, - * we need the M_LOOP flag since icmp6_error() expects - * the IPv6 and the hop-by-hop options header are - * continuous unless the flag is set. - */ - m->m_flags |= M_LOOP; - m->m_pkthdr.rcvif = ifp; - if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1), - ((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh), - &dummy1, &dummy2) < 0) { + if (ip6_hopopts_input(&dummy1, &dummy2, &m, &hoff)) { /* m was already freed at this point */ error = EINVAL;/* better error? */ goto done; } - m->m_flags &= ~M_LOOP; /* XXX */ - m->m_pkthdr.rcvif = NULL; + + ip6 = mtod(m, struct ip6_hdr *); } #ifdef PFIL_HOOKS Index: src/sys/netinet6/ip6_var.h diff -u src/sys/netinet6/ip6_var.h:1.56 src/sys/netinet6/ip6_var.h:1.57 --- src/sys/netinet6/ip6_var.h:1.56 Fri Nov 4 00:22:33 2011 +++ src/sys/netinet6/ip6_var.h Tue Jan 10 20:01:56 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_var.h,v 1.56 2011/11/04 00:22:33 zoltan Exp $ */ +/* $NetBSD: ip6_var.h,v 1.57 2012/01/10 20:01:56 drochner Exp $ */ /* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ /* @@ -327,8 +327,7 @@ struct m_tag *ip6_findaux(struct mbuf *) void ip6_delaux(struct mbuf *); int ip6_mforward(struct ip6_hdr *, struct ifnet *, struct mbuf *); -int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *, - u_int32_t *); +int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); void ip6_savecontrol(struct in6pcb *, struct mbuf **, struct ip6_hdr *, struct mbuf *); void ip6_notify_pmtu(struct in6pcb *, const struct sockaddr_in6 *, Index: src/sys/netipsec/ipsec_output.c diff -u src/sys/netipsec/ipsec_output.c:1.37 src/sys/netipsec/ipsec_output.c:1.38 --- src/sys/netipsec/ipsec_output.c:1.37 Wed Aug 31 18:31:03 2011 +++ src/sys/netipsec/ipsec_output.c Tue Jan 10 20:01:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_output.c,v 1.37 2011/08/31 18:31:03 plunky Exp $ */ +/* $NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $ */ /*- * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.37 2011/08/31 18:31:03 plunky Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.38 2012/01/10 20:01:57 drochner Exp $"); /* * IPsec output processing. @@ -632,6 +632,74 @@ bad: #endif #ifdef INET6 +static void +compute_ipsec_pos(struct mbuf *m, int *i, int *off) +{ + int nxt; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr*); + struct ip6_ext ip6e; + int dstopt = 0; + + *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. + */ + return; + + 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) + return; + + 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), &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: + return; + } + } while (*i < m->m_pkthdr.len); +} + static int in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) { @@ -731,8 +799,7 @@ ipsec6_process_packet( i = ip->ip_hl << 2; off = offsetof(struct ip, ip_p); } else { - i = sizeof(struct ip6_hdr); - off = offsetof(struct ip6_hdr, ip6_nxt); + compute_ipsec_pos(m, &i, &off); } error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); splx(s); Index: src/sys/netipsec/xform_ah.c diff -u src/sys/netipsec/xform_ah.c:1.33 src/sys/netipsec/xform_ah.c:1.34 --- src/sys/netipsec/xform_ah.c:1.33 Tue May 24 19:10:08 2011 +++ src/sys/netipsec/xform_ah.c Tue Jan 10 20:01:57 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: xform_ah.c,v 1.33 2011/05/24 19:10:08 drochner Exp $ */ +/* $NetBSD: xform_ah.c,v 1.34 2012/01/10 20:01:57 drochner Exp $ */ /* $FreeBSD: src/sys/netipsec/xform_ah.c,v 1.1.4.1 2003/01/24 05:11:36 sam Exp $ */ /* $OpenBSD: ip_ah.c,v 1.63 2001/06/26 06:18:58 angelos Exp $ */ /* @@ -39,7 +39,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.33 2011/05/24 19:10:08 drochner Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v 1.34 2012/01/10 20:01:57 drochner Exp $"); #include "opt_inet.h" #ifdef __FreeBSD__ @@ -72,6 +72,7 @@ __KERNEL_RCSID(0, "$NetBSD: xform_ah.c,v #ifdef INET6 #include <netinet6/ip6_var.h> +#include <netinet6/scope6_var.h> #include <netipsec/ipsec6.h> # ifdef __FreeBSD__ # include <netinet6/ip6_ecn.h> @@ -279,7 +280,7 @@ ah_massage_headers(struct mbuf **m0, int #ifdef INET6 struct ip6_ext *ip6e; struct ip6_hdr ip6; - int alloc, len, ad; + int alloc, ad, nxt; #endif /* INET6 */ switch (proto) { @@ -501,28 +502,28 @@ ah_massage_headers(struct mbuf **m0, int } 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)) { m_freem(m); @@ -554,8 +555,8 @@ ah_massage_headers(struct mbuf **m0, int } /* 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: @@ -563,10 +564,47 @@ ah_massage_headers(struct mbuf **m0, int * Always include routing headers in * computation. */ - ip6e = (struct ip6_ext *) (ptr + len); - len += ((ip6e->ip6e_len + 1) << 3); - off = ip6e->ip6e_nxt; - break; + { + 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++) + in6_clearscope(&addr[i]); + + finaldst = addr[rh0->ip6r0_segleft - 1]; + memmove(&addr[1], &addr[0], + sizeof(struct in6_addr) * + (rh0->ip6r0_segleft - 1)); + + m_copydata(m, 0, sizeof(ip6), &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 "