summaryrefslogtreecommitdiff
path: root/sys/netinet
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2012-03-15 16:37:12 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2012-03-15 16:37:12 +0000
commitf691a48ee80ba746816d740ae0db5392c17d24c9 (patch)
tree052795a75d64c1dc64bc1912609e4031721ce304 /sys/netinet
parente4afdbb46f47650f9cc49d61eb48ad859fbaf606 (diff)
improve IPsec/ENC interaction:
- ipip_input() recalculate the IP header checksum if the tos bits are changed after decapsulation. Otherwise these packets are dropped later in the stack. - ip_ecn_egress(): do not drop packets for IPsec if the outter packet of a Tunnel has the ECN-CE bit set (Congestion Experienced) and the inner packet does not indicate support ECN. - remove unused ip6_ecn_ingress(), ip6_ecn_egress() code ok mikeb@
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_ecn.c55
-rw-r--r--sys/netinet/ip_ecn.h13
-rw-r--r--sys/netinet/ip_ipip.c24
3 files changed, 35 insertions, 57 deletions
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
index 6f3a1f49e6a..1c08f9514c7 100644
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ecn.c,v 1.4 2002/05/16 14:10:51 kjc Exp $ */
+/* $OpenBSD: ip_ecn.c,v 1.5 2012/03/15 16:37:11 markus Exp $ */
/* $KAME: ip_ecn.c,v 1.9 2000/10/01 12:44:48 itojun Exp $ */
/*
@@ -101,6 +101,7 @@ ip_ecn_ingress(mode, outer, inner)
*outer = *inner;
switch (mode) {
case ECN_ALLOWED: /* ECN allowed */
+ case ECN_ALLOWED_IPSEC:
/*
* full-functionality: if the inner is CE, set ECT(0)
* to the outer. otherwise, copy the ECN field.
@@ -135,13 +136,20 @@ ip_ecn_egress(mode, outer, inner)
switch (mode) {
case ECN_ALLOWED:
+ case ECN_ALLOWED_IPSEC:
/*
* full-functionality: if the outer is CE and the inner is
* not-ECT, should drop it. otherwise, copy CE.
+ * However, according to RFC4301, we should just leave the
+ * inner as non-ECT for IPsec.
*/
if ((*outer & IPTOS_ECN_MASK) == IPTOS_ECN_CE) {
- if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT)
- return (0);
+ if ((*inner & IPTOS_ECN_MASK) == IPTOS_ECN_NOTECT) {
+ if (mode == ECN_ALLOWED_IPSEC)
+ return (1);
+ else
+ return (0);
+ }
*inner |= IPTOS_ECN_CE;
}
break;
@@ -158,44 +166,3 @@ ip_ecn_egress(mode, outer, inner)
}
return (1);
}
-
-#ifdef INET6
-void
-ip6_ecn_ingress(mode, outer, inner)
- int mode;
- u_int32_t *outer;
- u_int32_t *inner;
-{
- u_int8_t outer8, inner8;
-
- if (!outer || !inner)
- panic("NULL pointer passed to ip6_ecn_ingress");
-
- inner8 = (ntohl(*inner) >> 20) & 0xff;
- ip_ecn_ingress(mode, &outer8, &inner8);
- *outer &= ~htonl(0xff << 20);
- *outer |= htonl((u_int32_t)outer8 << 20);
-}
-
-int
-ip6_ecn_egress(mode, outer, inner)
- int mode;
- u_int32_t *outer;
- u_int32_t *inner;
-{
- u_int8_t outer8, inner8, oinner8;
-
- if (!outer || !inner)
- panic("NULL pointer passed to ip6_ecn_egress");
-
- outer8 = (ntohl(*outer) >> 20) & 0xff;
- inner8 = oinner8 = (ntohl(*inner) >> 20) & 0xff;
- if (ip_ecn_egress(mode, &outer8, &inner8) == 0)
- return (0);
- if (inner8 != oinner8) {
- *inner &= ~htonl(0xff << 20);
- *inner |= htonl((u_int32_t)inner8 << 20);
- }
- return (1);
-}
-#endif
diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h
index 7c8a0e615c2..d6a8b166f1a 100644
--- a/sys/netinet/ip_ecn.h
+++ b/sys/netinet/ip_ecn.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ecn.h,v 1.5 2002/05/16 14:10:51 kjc Exp $ */
+/* $OpenBSD: ip_ecn.h,v 1.6 2012/03/15 16:37:11 markus Exp $ */
/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */
/*
@@ -39,16 +39,13 @@
* http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt
*/
-#define ECN_ALLOWED 1 /* ECN allowed */
-#define ECN_FORBIDDEN 0 /* ECN forbidden */
-#define ECN_NOCARE (-1) /* no consideration to ECN */
+#define ECN_ALLOWED_IPSEC 2 /* ECN allowed */
+#define ECN_ALLOWED 1 /* ECN allowed */
+#define ECN_FORBIDDEN 0 /* ECN forbidden */
+#define ECN_NOCARE (-1) /* no consideration to ECN */
#if defined(_KERNEL)
extern void ip_ecn_ingress(int, u_int8_t *, u_int8_t *);
extern int ip_ecn_egress(int, u_int8_t *, u_int8_t *);
-#ifdef INET6
-extern void ip6_ecn_ingress(int, u_int32_t *, u_int32_t *);
-extern int ip6_ecn_egress(int, u_int32_t *, u_int32_t *);
-#endif /* INET6 */
#endif /* _KERNEL */
#endif /* _NETINET_IP_ECN_H_ */
diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c
index 6a48e52bb0b..24e89044b67 100644
--- a/sys/netinet/ip_ipip.c
+++ b/sys/netinet/ip_ipip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipip.c,v 1.47 2010/05/11 09:36:07 claudio Exp $ */
+/* $OpenBSD: ip_ipip.c,v 1.48 2012/03/15 16:37:11 markus Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -156,11 +156,10 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto)
#ifdef INET6
struct sockaddr_in6 *sin6;
struct ip6_hdr *ip6;
- u_int8_t itos;
#endif
int isr;
- int hlen, s;
- u_int8_t otos;
+ int mode, hlen, s;
+ u_int8_t itos, otos;
u_int8_t v;
sa_family_t af;
@@ -266,10 +265,23 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto)
#ifdef INET6
ip6 = NULL;
#endif
- if (!ip_ecn_egress(ECN_ALLOWED, &otos, &ipo->ip_tos)) {
+ itos = ipo->ip_tos;
+ mode = m->m_flags & (M_AUTH|M_CONF) ?
+ ECN_ALLOWED_IPSEC : ECN_ALLOWED;
+ if (!ip_ecn_egress(mode, &otos, &ipo->ip_tos)) {
+ DPRINTF(("ipip_input(): ip_ecn_egress() failed"));
+ ipipstat.ipips_pdrops++;
m_freem(m);
return;
}
+ /* re-calculate the checksum if ip_tos was changed */
+ if (itos != ipo->ip_tos) {
+ hlen = ipo->ip_hl << 2;
+ if (m->m_pkthdr.len >= hlen) {
+ ipo->ip_sum = 0;
+ ipo->ip_sum = in_cksum(m, hlen);
+ }
+ }
break;
#endif /* INET */
#ifdef INET6
@@ -280,6 +292,8 @@ ipip_input(struct mbuf *m, int iphlen, struct ifnet *gifp, int proto)
ip6 = mtod(m, struct ip6_hdr *);
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) {
+ DPRINTF(("ipip_input(): ip_ecn_egress() failed"));
+ ipipstat.ipips_pdrops++;
m_freem(m);
return;
}