summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordlg <dlg@openbsd.org>2018-11-14 23:55:04 +0000
committerdlg <dlg@openbsd.org>2018-11-14 23:55:04 +0000
commit412c1a0a3243808d61b48f36fcd52ec7142f1817 (patch)
treefb9c043fa312365d30f9109d45b384d49b0ea711
parentWarn on deprecated 'vlan' and 'vlandev' option usage (diff)
downloadwireguard-openbsd-412c1a0a3243808d61b48f36fcd52ec7142f1817.tar.xz
wireguard-openbsd-412c1a0a3243808d61b48f36fcd52ec7142f1817.zip
provide ip_tos_patch() for setting ip_tos and patching the ipv4 cksum.
previously the gif code would patch the tos field and not recalc the cksum, which would cause ip input code to drop the packet due to a cksum failure. the ipip code patched ip_tos and unconditionally recalculated the cksum, making it correct, but also wiping out any errors that may have been present before the recalculation. updating the cksum rather than replacing it lets cksum failures still fire. ip_tos_patch() is provided in the ecn code since it's because of ecn propagation that we need to update the tos field. internally it works like pf_patch_8 and pf_cksum_fixup, but since pf is optional it rolls its own code. procter may fix that in the future... ok claudio@
-rw-r--r--sys/net/if_gif.c5
-rw-r--r--sys/netinet/ip_ecn.c23
-rw-r--r--sys/netinet/ip_ecn.h3
-rw-r--r--sys/netinet/ip_ipip.c10
4 files changed, 31 insertions, 10 deletions
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 093c4a95153..abec736b180 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gif.c,v 1.123 2018/11/14 03:20:03 dlg Exp $ */
+/* $OpenBSD: if_gif.c,v 1.124 2018/11/14 23:55:04 dlg Exp $ */
/* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */
/*
@@ -809,7 +809,8 @@ gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto,
if (ip_ecn_egress(ECN_ALLOWED, &otos, &itos) == 0)
goto drop;
- ip->ip_tos = itos;
+ if (itos != ip->ip_tos)
+ ip_tos_patch(ip, itos);
m->m_pkthdr.ph_family = AF_INET;
input = ipv4_input;
diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c
index e5d6cf249bb..b4621a019f1 100644
--- a/sys/netinet/ip_ecn.c
+++ b/sys/netinet/ip_ecn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ecn.c,v 1.8 2016/09/24 14:51:37 naddy Exp $ */
+/* $OpenBSD: ip_ecn.c,v 1.9 2018/11/14 23:55:04 dlg Exp $ */
/* $KAME: ip_ecn.c,v 1.9 2000/10/01 12:44:48 itojun Exp $ */
/*
@@ -154,3 +154,24 @@ ip_ecn_egress(int mode, u_int8_t *outer, u_int8_t *inner)
}
return (1);
}
+
+/*
+ * Patch the checksum with the difference between the old and new tos.
+ * The patching is based on what pf_patch_8() and pf_cksum_fixkup() do,
+ * but they're in pf, so we can't rely on them being available.
+ */
+void
+ip_tos_patch(struct ip *ip, uint8_t tos)
+{
+ uint16_t old;
+ uint16_t new;
+ uint32_t x;
+
+ old = htons(ip->ip_tos);
+ new = htons(tos);
+
+ ip->ip_tos = tos;
+
+ x = ip->ip_sum + old - new;
+ ip->ip_sum = (x) + (x >> 16);
+}
diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h
index d6a8b166f1a..6f3d552468f 100644
--- a/sys/netinet/ip_ecn.h
+++ b/sys/netinet/ip_ecn.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ecn.h,v 1.6 2012/03/15 16:37:11 markus Exp $ */
+/* $OpenBSD: ip_ecn.h,v 1.7 2018/11/14 23:55:04 dlg Exp $ */
/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */
/*
@@ -47,5 +47,6 @@
#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 *);
+void ip_tos_patch(struct ip *, uint8_t);
#endif /* _KERNEL */
#endif /* _NETINET_IP_ECN_H_ */
diff --git a/sys/netinet/ip_ipip.c b/sys/netinet/ip_ipip.c
index 60d6efdc284..b8c90fd702e 100644
--- a/sys/netinet/ip_ipip.c
+++ b/sys/netinet/ip_ipip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip_ipip.c,v 1.88 2018/08/28 15:15:02 mpi Exp $ */
+/* $OpenBSD: ip_ipip.c,v 1.89 2018/11/14 23:55:04 dlg Exp $ */
/*
* The authors of this code are John Ioannidis (ji@tla.org),
* Angelos D. Keromytis (kermit@csd.uch.gr) and
@@ -239,16 +239,14 @@ ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf,
itos = ip->ip_tos;
mode = m->m_flags & (M_AUTH|M_CONF) ?
ECN_ALLOWED_IPSEC : ECN_ALLOWED;
- if (!ip_ecn_egress(mode, &otos, &ip->ip_tos)) {
+ if (!ip_ecn_egress(mode, &otos, &itos)) {
DPRINTF(("%s: ip_ecn_egress() failed\n", __func__));
ipipstat_inc(ipips_pdrops);
goto bad;
}
/* re-calculate the checksum if ip_tos was changed */
- if (itos != ip->ip_tos) {
- ip->ip_sum = 0;
- ip->ip_sum = in_cksum(m, hlen);
- }
+ if (itos != ip->ip_tos)
+ ip_tos_patch(ip, itos);
break;
#ifdef INET6
case IPPROTO_IPV6: