git: 301bff9bdd62 - stable/13 - ppp: improve MSS clamping

From: Michael Tuexen <tuexen_at_FreeBSD.org>
Date: Thu, 02 Feb 2023 00:04:15 UTC
The branch stable/13 has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=301bff9bdd628f27af7d0a6cda440b9525fde336

commit 301bff9bdd628f27af7d0a6cda440b9525fde336
Author:     Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2022-12-08 08:48:29 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2023-02-02 00:03:50 +0000

    ppp: improve MSS clamping
    
    ppp supports MSS clamping for TCP/IPv4. This patch
    * improves MSS clamping for TCP/IPv4 by using the MSS as specified
      in RFC 6691.
    * adds support for MSS clamping for TCP/IPv6.
    
    Reported by:            Timo Voelker
    Reviewed by:            thj
    Differential Revision:  https://reviews.freebsd.org/D37624
    
    (cherry picked from commit cef3c4e0bab8bd5e84ab8cfa2fa48a1e3dca5876)
---
 usr.sbin/ppp/tcpmss.c | 76 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 62 insertions(+), 14 deletions(-)

diff --git a/usr.sbin/ppp/tcpmss.c b/usr.sbin/ppp/tcpmss.c
index 765668e9d137..cbf85dbf2a09 100644
--- a/usr.sbin/ppp/tcpmss.c
+++ b/usr.sbin/ppp/tcpmss.c
@@ -35,6 +35,9 @@
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#ifndef NOINET6
+#include <netinet/ip6.h>
+#endif
 #include <netinet/tcp.h>
 #include <sys/un.h>
 
@@ -69,10 +72,12 @@
 
 
 /*-
- * We are in a liberal position about MSS
- * (RFC 879, section 7).
+ * Compute the MSS as described in RFC 6691.
  */
-#define MAXMSS(mtu) ((mtu) - sizeof(struct ip) - sizeof(struct tcphdr) - 12)
+#define MAXMSS4(mtu) ((mtu) - sizeof(struct ip) - sizeof(struct tcphdr))
+#ifndef NOINET6
+#define MAXMSS6(mtu) ((mtu) - sizeof(struct ip6_hdr) - sizeof(struct tcphdr))
+#endif
 
 
 /*-
@@ -146,6 +151,10 @@ static struct mbuf *
 tcpmss_Check(struct bundle *bundle, struct mbuf *bp)
 {
   struct ip *pip;
+#ifndef NOINET6
+  struct ip6_hdr *pip6;
+  struct ip6_frag *pfrag;
+#endif
   size_t hlen, plen;
 
   if (!Enabled(bundle, OPT_TCPMSSFIXUP))
@@ -153,19 +162,58 @@ tcpmss_Check(struct bundle *bundle, struct mbuf *bp)
 
   bp = m_pullup(bp);
   plen = m_length(bp);
+  if (plen < sizeof(struct ip))
+    return bp;
   pip = (struct ip *)MBUF_CTOP(bp);
-  hlen = pip->ip_hl << 2;
-
-  /*
-   * Check for MSS option only for TCP packets with zero fragment offsets
-   * and correct total and header lengths.
-   */
-  if (pip->ip_p == IPPROTO_TCP && (ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
-      ntohs(pip->ip_len) == plen && hlen <= plen &&
-      plen >= sizeof(struct tcphdr) + hlen)
-    MSSFixup((struct tcphdr *)(MBUF_CTOP(bp) + hlen), plen - hlen,
-             MAXMSS(bundle->iface->mtu));
 
+  switch (pip->ip_v) {
+  case IPVERSION:
+    /*
+     * Check for MSS option only for TCP packets with zero fragment offsets
+     * and correct total and header lengths.
+     */
+    hlen = pip->ip_hl << 2;
+    if (pip->ip_p == IPPROTO_TCP && (ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
+        ntohs(pip->ip_len) == plen && hlen <= plen &&
+        plen >= sizeof(struct tcphdr) + hlen)
+      MSSFixup((struct tcphdr *)(MBUF_CTOP(bp) + hlen), plen - hlen,
+               MAXMSS4(bundle->iface->mtu));
+    break;
+#ifndef NOINET6
+  case IPV6_VERSION >> 4:
+    /*
+     * Check for MSS option only for TCP packets with no extension headers
+     * or a single extension header which is a fragmentation header with
+     * offset 0. Furthermore require that the length field is correct.
+     */
+    if (plen < sizeof(struct ip6_hdr))
+      break;
+    pip6 = (struct ip6_hdr *)MBUF_CTOP(bp);
+    if (ntohs(pip6->ip6_plen) + sizeof(struct ip6_hdr) != plen)
+      break;
+    hlen = 0;
+    switch (pip6->ip6_nxt) {
+    case IPPROTO_TCP:
+      hlen = sizeof(struct ip6_hdr);
+      break;
+    case IPPROTO_FRAGMENT:
+      if (plen >= sizeof(struct ip6_frag) + sizeof(struct ip6_hdr)) {
+        pfrag = (struct ip6_frag *)(MBUF_CTOP(bp) + sizeof(struct ip6_hdr));
+        if (pfrag->ip6f_nxt == IPPROTO_TCP &&
+            ntohs(pfrag->ip6f_offlg & IP6F_OFF_MASK) == 0)
+          hlen = sizeof(struct ip6_hdr)+ sizeof(struct ip6_frag);
+      }
+      break;
+    }
+    if (hlen > 0 && plen >= sizeof(struct tcphdr) + hlen)
+      MSSFixup((struct tcphdr *)(MBUF_CTOP(bp) + hlen), plen - hlen,
+               MAXMSS6(bundle->iface->mtu));
+    break;
+#endif
+  default:
+    log_Printf(LogDEBUG, "tcpmss_Check: Unknown IP family %u\n", pip->ip_v);
+    break;
+  }
   return bp;
 }