hotfix(pmtud): lower min MTU to MSS-matching-MTU minus 100 in case MSS is very small

This commit is contained in:
Quentin McGaw
2026-02-19 22:39:24 +00:00
parent 2192874de8
commit ea87c0a2aa
2 changed files with 21 additions and 14 deletions
+1 -1
View File
@@ -66,7 +66,7 @@ func PathMTUDiscover(ctx context.Context, icmpAddrs []netip.Addr, tcpAddrs []net
minMTU = constants.MinIPv6MTU minMTU = constants.MinIPv6MTU
} }
if icmpSuccess { if icmpSuccess {
const mtuMargin = 300 const mtuMargin = 150
minMTU = max(maxPossibleMTU-mtuMargin, minMTU) minMTU = max(maxPossibleMTU-mtuMargin, minMTU)
} }
mtu, err = tcp.PathMTUDiscover(ctx, tcpAddrs, minMTU, maxPossibleMTU, tryTimeout, fw, logger) mtu, err = tcp.PathMTUDiscover(ctx, tcpAddrs, minMTU, maxPossibleMTU, tryTimeout, fw, logger)
+20 -13
View File
@@ -12,7 +12,10 @@ import (
"github.com/qdm12/gluetun/internal/pmtud/test" "github.com/qdm12/gluetun/internal/pmtud/test"
) )
var ErrMTUNotFound = errors.New("MTU not found") var (
ErrMTUNotFound = errors.New("MTU not found")
ErrMSSTooSmall = errors.New("TCP MSS is too small to find the MTU")
)
type testUnit struct { type testUnit struct {
mtu uint32 mtu uint32
@@ -63,24 +66,28 @@ func PathMTUDiscover(ctx context.Context, dsts []netip.AddrPort,
maxPossibleMTU, tryTimeout, tracker, firewall, logger) maxPossibleMTU, tryTimeout, tracker, firewall, logger)
mssResultCh <- mssResult{dst: dst, mss: mss, err: err} mssResultCh <- mssResult{dst: dst, mss: mss, err: err}
}() }()
var highestMSSDst netip.AddrPort var result mssResult
select { select {
case err = <-trackerErrCh: case err = <-trackerErrCh:
mssCancel() mssCancel()
<-mssResultCh <-mssResultCh
return 0, fmt.Errorf("listening for TCP replies: %w", err) return 0, fmt.Errorf("listening for TCP replies: %w", err)
case result := <-mssResultCh: case result = <-mssResultCh:
if result.err != nil { }
trackerCancel() if result.err != nil {
<-trackerErrCh trackerCancel()
return 0, fmt.Errorf("finding MSS: %w", result.err) <-trackerErrCh
} return 0, fmt.Errorf("finding MSS: %w", result.err)
highestMSSDst = result.dst }
ipHeaderLength := ip.HeaderLength(highestMSSDst.Addr().Is4()) ipHeaderLength := ip.HeaderLength(result.dst.Addr().Is4())
maxPossibleMTU = ipHeaderLength + constants.BaseTCPHeaderLength + result.mss maxPossibleMTU = ipHeaderLength + constants.BaseTCPHeaderLength + result.mss
if minMTU > maxPossibleMTU {
// Occasionally, the MSS is a lot smaller than the MTU found using ICMP
const safetyBuffer = 100
minMTU = maxPossibleMTU - safetyBuffer
} }
fd := familyToFD[ip.GetFamily(highestMSSDst)] fd := familyToFD[ip.GetFamily(result.dst)]
type pmtudResult struct { type pmtudResult struct {
mtu uint32 mtu uint32
@@ -90,7 +97,7 @@ func PathMTUDiscover(ctx context.Context, dsts []netip.AddrPort,
pmtudCtx, pmtudCancel := context.WithCancel(ctx) pmtudCtx, pmtudCancel := context.WithCancel(ctx)
defer pmtudCancel() defer pmtudCancel()
go func() { go func() {
mtu, err := pathMTUDiscover(pmtudCtx, fd, highestMSSDst, minMTU, maxPossibleMTU, mtu, err := pathMTUDiscover(pmtudCtx, fd, result.dst, minMTU, maxPossibleMTU,
excludeMark, tryTimeout, tracker, firewall, logger) excludeMark, tryTimeout, tracker, firewall, logger)
resultCh <- pmtudResult{mtu: mtu, err: err} resultCh <- pmtudResult{mtu: mtu, err: err}
}() }()