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 "

Reply via email to