Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/net/npf Introduce npf_set_mss(). When the MSS is not 16b...
details: https://anonhg.NetBSD.org/src/rev/814892dae96f
branches: trunk
changeset: 366518:814892dae96f
user: maxv <maxv%NetBSD.org@localhost>
date: Fri Aug 31 14:16:06 2018 +0000
description:
Introduce npf_set_mss(). When the MSS is not 16bit-aligned, it sets:
0 8 16 24 32
+------+-----------+-----------+------+
| data | MSS (low) | MSS (hig) | data |
+------+-----------+-----------+------+
^ ^
old[0] old[1]
And sets new[0,1] accordingly with the new value. The MSS-clamping code
then adjusts twice the checksum on a 16bit boundary:
from old[0] to new[0]
from old[1] to new[1]
Fixes PR/53479, opened by myself. Tested with wireshark and kASan.
diffstat:
sys/net/npf/npf_ext_normalize.c | 21 +++++++--
sys/net/npf/npf_impl.h | 4 +-
sys/net/npf/npf_inet.c | 92 +++++++++++++++++++++++++++++++++++-----
3 files changed, 98 insertions(+), 19 deletions(-)
diffs (207 lines):
diff -r 2f25efa74642 -r 814892dae96f sys/net/npf/npf_ext_normalize.c
--- a/sys/net/npf/npf_ext_normalize.c Fri Aug 31 11:21:00 2018 +0000
+++ b/sys/net/npf/npf_ext_normalize.c Fri Aug 31 14:16:06 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_ext_normalize.c,v 1.7 2018/04/07 09:20:25 maxv Exp $ */
+/* $NetBSD: npf_ext_normalize.c,v 1.8 2018/08/31 14:16:06 maxv Exp $ */
/*-
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ext_normalize.c,v 1.7 2018/04/07 09:20:25 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ext_normalize.c,v 1.8 2018/08/31 14:16:06 maxv Exp $");
#include <sys/types.h>
#include <sys/module.h>
@@ -148,8 +148,10 @@
{
npf_normalize_t *np = params;
uint16_t cksum, mss, maxmss = np->n_maxmss;
+ uint16_t old[2], new[2];
struct tcphdr *th;
int wscale;
+ bool mid;
/* Skip, if already blocking. */
if (*decision == NPF_DECISION_BLOCK) {
@@ -182,13 +184,22 @@
maxmss = htons(maxmss);
/*
- * Store new MSS, calculate TCP checksum and update it.
+ * Store new MSS, calculate TCP checksum and update it. The MSS may
+ * not be aligned and fall in the middle of two uint16_t's, so we
+ * need to take care of that when calculating the checksum.
+ *
* WARNING: must re-fetch the TCP header after the modification.
*/
- if (npf_fetch_tcpopts(npc, &maxmss, &wscale) &&
+ if (npf_set_mss(npc, maxmss, old, new, &mid) &&
!nbuf_cksum_barrier(npc->npc_nbuf, mi->mi_di)) {
th = npc->npc_l4.tcp;
- cksum = npf_fixup16_cksum(th->th_sum, mss, maxmss);
+ if (mid) {
+ cksum = th->th_sum;
+ cksum = npf_fixup16_cksum(cksum, old[0], new[0]);
+ cksum = npf_fixup16_cksum(cksum, old[1], new[1]);
+ } else {
+ cksum = npf_fixup16_cksum(th->th_sum, mss, maxmss);
+ }
th->th_sum = cksum;
}
diff -r 2f25efa74642 -r 814892dae96f sys/net/npf/npf_impl.h
--- a/sys/net/npf/npf_impl.h Fri Aug 31 11:21:00 2018 +0000
+++ b/sys/net/npf/npf_impl.h Fri Aug 31 14:16:06 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_impl.h,v 1.70 2017/12/10 01:18:21 rmind Exp $ */
+/* $NetBSD: npf_impl.h,v 1.71 2018/08/31 14:16:06 maxv Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -283,6 +283,8 @@
int npf_tcpsaw(const npf_cache_t *, tcp_seq *, tcp_seq *,
uint32_t *);
bool npf_fetch_tcpopts(npf_cache_t *, uint16_t *, int *);
+bool npf_set_mss(npf_cache_t *, uint16_t, uint16_t *, uint16_t *,
+ bool *);
bool npf_return_block(npf_cache_t *, const int);
/* BPF interface. */
diff -r 2f25efa74642 -r 814892dae96f sys/net/npf/npf_inet.c
--- a/sys/net/npf/npf_inet.c Fri Aug 31 11:21:00 2018 +0000
+++ b/sys/net/npf/npf_inet.c Fri Aug 31 14:16:06 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_inet.c,v 1.50 2018/04/08 05:51:45 maxv Exp $ */
+/* $NetBSD: npf_inet.c,v 1.51 2018/08/31 14:16:06 maxv Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.50 2018/04/08 05:51:45 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.51 2018/08/31 14:16:06 maxv Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -230,7 +230,6 @@
nbuf_t *nbuf = npc->npc_nbuf;
const struct tcphdr *th = npc->npc_l4.tcp;
int cnt, optlen = 0;
- bool setmss = false;
uint8_t *cp, opt;
uint8_t val;
bool ok;
@@ -246,11 +245,6 @@
}
KASSERT(cnt <= MAX_TCPOPTLEN);
- /* Determine if we want to set or get the mss. */
- if (mss) {
- setmss = (*mss != 0);
- }
-
/* Fetch all the options at once. */
nbuf_reset(nbuf);
const int step = npc->npc_hlen + sizeof(struct tcphdr);
@@ -279,11 +273,7 @@
if (optlen != TCPOLEN_MAXSEG)
continue;
if (mss) {
- if (setmss) {
- memcpy(cp + 2, mss, sizeof(uint16_t));
- } else {
- memcpy(mss, cp + 2, sizeof(uint16_t));
- }
+ memcpy(mss, cp + 2, sizeof(uint16_t));
}
break;
case TCPOPT_WINDOW:
@@ -305,6 +295,82 @@
return ok;
}
+/*
+ * npf_set_mss: set the MSS.
+ */
+bool
+npf_set_mss(npf_cache_t *npc, uint16_t mss, uint16_t *old, uint16_t *new,
+ bool *mid)
+{
+ nbuf_t *nbuf = npc->npc_nbuf;
+ const struct tcphdr *th = npc->npc_l4.tcp;
+ int cnt, optlen = 0;
+ uint8_t *cp, *base, opt;
+ bool ok;
+
+ KASSERT(npf_iscached(npc, NPC_IP46));
+ KASSERT(npf_iscached(npc, NPC_TCP));
+
+ /* Determine if there are any TCP options, get their length. */
+ cnt = (th->th_off << 2) - sizeof(struct tcphdr);
+ if (cnt <= 0) {
+ /* No options. */
+ return false;
+ }
+ KASSERT(cnt <= MAX_TCPOPTLEN);
+
+ /* Fetch all the options at once. */
+ nbuf_reset(nbuf);
+ const int step = npc->npc_hlen + sizeof(struct tcphdr);
+ if ((base = nbuf_advance(nbuf, step, cnt)) == NULL) {
+ ok = false;
+ goto done;
+ }
+
+ /* Scan the options. */
+ for (cp = base; cnt > 0; cnt -= optlen, cp += optlen) {
+ opt = cp[0];
+ if (opt == TCPOPT_EOL)
+ break;
+ if (opt == TCPOPT_NOP)
+ optlen = 1;
+ else {
+ if (cnt < 2)
+ break;
+ optlen = cp[1];
+ if (optlen < 2 || optlen > cnt)
+ break;
+ }
+
+ switch (opt) {
+ case TCPOPT_MAXSEG:
+ if (optlen != TCPOLEN_MAXSEG)
+ continue;
+ if (((cp + 2) - base) % sizeof(uint16_t) != 0) {
+ *mid = true;
+ memcpy(&old[0], cp + 1, sizeof(uint16_t));
+ memcpy(&old[1], cp + 3, sizeof(uint16_t));
+ memcpy(cp + 2, &mss, sizeof(uint16_t));
+ memcpy(&new[0], cp + 1, sizeof(uint16_t));
+ memcpy(&new[1], cp + 3, sizeof(uint16_t));
+ } else {
+ *mid = false;
+ memcpy(cp + 2, &mss, sizeof(uint16_t));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ ok = true;
+done:
+ if (nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)) {
+ npf_recache(npc);
+ }
+ return ok;
+}
+
static int
npf_cache_ip(npf_cache_t *npc, nbuf_t *nbuf)
{
Home |
Main Index |
Thread Index |
Old Index