diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2012-03-15 16:37:12 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2012-03-15 16:37:12 +0000 |
commit | f691a48ee80ba746816d740ae0db5392c17d24c9 (patch) | |
tree | 052795a75d64c1dc64bc1912609e4031721ce304 /sys/netinet | |
parent | e4afdbb46f47650f9cc49d61eb48ad859fbaf606 (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.c | 55 | ||||
-rw-r--r-- | sys/netinet/ip_ecn.h | 13 | ||||
-rw-r--r-- | sys/netinet/ip_ipip.c | 24 |
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; } |