aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2022-12-08 08:48:29 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2022-12-08 08:48:29 +0000
commitcef3c4e0bab8bd5e84ab8cfa2fa48a1e3dca5876 (patch)
tree4fb8cef5b7504fb3a70c7d16872944d428d3ea2b
parent70bb22868d534435fd8d84173f264b48acacd501 (diff)
downloadsrc-cef3c4e0bab8bd5e84ab8cfa2fa48a1e3dca5876.tar.gz
src-cef3c4e0bab8bd5e84ab8cfa2fa48a1e3dca5876.zip
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 MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D37624
-rw-r--r--usr.sbin/ppp/tcpmss.c76
1 files 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;
}