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 "