How to Perform MTU Discovery and Optimization in MasterDnsVPN
MasterDnsVPN automatically discovers the optimal Maximum Transmission Unit (MTU) for each DNS resolver through parallel binary-search probes, then synchronizes the minimum viable upload and download values across all active connections.
MasterDnsVPN implements a sophisticated VPN-over-DNS tunnel that requires precise packet sizing to prevent fragmentation and maximize throughput. The client performs MTU discovery and optimization automatically at startup by probing each configured resolver to determine the largest payload size that can traverse the network path without fragmentation. This process stores synced upload and download MTU values—accessed via c.syncedUploadMTU and c.syncedDownloadMTU—that govern all subsequent traffic for the session.
Understanding the MTU Discovery Pipeline
The discovery process executes in three distinct stages defined in internal/client/mtu.go. When the client initializes, RunInitialMTUTests (starting at line 85) orchestrates the entire workflow:
- Stage 1: Create worker pools and pre-compute upload capacity limits via
precomputeUploadCaps() - Stage 2: Execute independent binary searches for upload and download MTU per resolver
- Stage 3: Aggregate results and apply minimum viable values via
applySyncedMTUState
The system uses c.cfg.EffectiveMTUTestParallelism() (defaulting to 1) to control concurrency, ensuring tests run efficiently without overwhelming upstream DNS resolvers.
Stage 1: Initializing Test Runs with RunInitialMTUTests
The RunInitialMTUTests function (lines 85-100 in internal/client/mtu.go) prepares the MTU discovery environment. It calculates the maximum upload payload each domain can support, then initializes a worker pool sized according to your MTUTestParallelism configuration.
func (c *Client) RunInitialMTUTests(ctx context.Context) error {
uploadCaps := c.precomputeUploadCaps()
workerCount := min(max(1, c.cfg.EffectiveMTUTestParallelism()), len(scanConnections))
c.logMTUStart(workerCount)
c.prepareMTUSuccessOutputFile()
// Workers execute runConnectionMTUTest for each resolver
}
This stage also prepares optional logging infrastructure. If you configure MTU_SERVERS_FILE_NAME, the client initializes file handles in internal/client/mtu_logging.go to persist results.
Stage 2: Binary Search Probing
For each active resolver connection, the client executes runConnectionMTUTest, which performs separate binary searches for upload and download capabilities using the generic binarySearchMTU algorithm (lines 143-191).
Upload MTU Probing
The upload probe uses sendUploadMTUProbe (lines 109-143) to validate MTU candidates. The function builds a DNS TXT query containing a random probe code (mtuProbeCodeLength = 4 bytes) and the candidate size.
best, bestRTT := c.binarySearchMTU(
ctx,
"upload mtu",
c.cfg.MinUploadMTU, // Configurable lower bound
maxPayload, // Upper bound (capped to MaxUploadMTU or 512)
minUploadMTUFloor,
func(candidate int, isRetry bool) (bool, time.Duration, error) {
return c.sendUploadMTUProbe(ctx, conn, probeTransport,
candidate, c.mtuTestTimeout,
mtuProbeOptions{IsRetry: isRetry})
})
The probe succeeds when DnsParser.ExtractVPNResponse validates the echoed probe code and size. The binary search converges on the highest viable upload MTU that receives valid responses.
Download MTU Probing
Download discovery follows a similar pattern but accounts for response overhead. The sendDownloadMTUProbe function (lines 158-210) first sends an upload probe to prime the remote side, then requests an echo of a larger payload. The effective download size includes a fixed mtuDownResponseReserve reservation.
best, bestRTT := c.binarySearchMTU(
ctx,
"download mtu",
c.cfg.MinDownloadMTU,
c.cfg.MaxDownloadMTU,
minDownloadMTUFloor,
func(candidate int, isRetry bool) (bool, time.Duration, error) {
return c.sendDownloadMTUProbe(ctx, conn, probeTransport,
candidate, uploadMTU,
c.mtuTestTimeout,
mtuProbeOptions{IsRetry: isRetry})
})
The algorithm validates that the response payload length matches the expected effectiveDownloadMTUProbeSize, ensuring the path can handle downstream packets of that size.
Stage 3: Applying Synchronized MTU State
After all workers complete, applySyncedMTUState (called from line 146) processes the aggregated results. The client examines all connections through c.balancer.ActiveConnections() and selects the minimum upload MTU and minimum download MTU found among valid connections.
validConns, minUpload, minDownload, minUploadChars := summarizeValidMTUConnections(activeConns)
c.applySyncedMTUState(minUpload, minDownload, minUploadChars)
These values populate c.syncedUploadMTU and c.syncedDownloadMTU, which subsequently constrain all VPN traffic. The selection of minimum values ensures compatibility with the most restrictive resolver in your pool, preventing fragmentation on any active path.
Configuring MTU Discovery Parameters
You can customize the discovery behavior through the client configuration struct defined in internal/config/client.go. The following JSON example demonstrates key parameters:
{
"MinUploadMTU": 64,
"MaxUploadMTU": 512,
"MinDownloadMTU": 64,
"MaxDownloadMTU": 1500,
"MTUTestParallelism": 4,
"MTU_SERVERS_FILE_NAME": "mtu_results_{time}.log"
}
- MinUploadMTU/MaxUploadMTU: Bound the upload binary search range (default maximum is 512 bytes)
- MinDownloadMTU/MaxDownloadMTU: Control the download probe limits
- MTUTestParallelism: Number of concurrent resolver tests (default 1)
- MTU_SERVERS_FILE_NAME: Optional file path for persisting results;
{time}expands to a timestamp
Interpreting MTU Log Output
When MTU_SERVERS_FILE_NAME is configured, internal/client/mtu_logging.go writes results using the template "{IP} - UP: {UP_MTU} DOWN: {DOWN-MTU}". A typical entry appears as:
192.0.2.53 - UP: 112 - DOWN: 1024
- UP: Raw bytes available for upload payloads in a single DNS query
- DOWN: Raw bytes available for download payloads, including the reserved response trailer
These values represent the actual payload capacity after DNS protocol overhead, not the wire-size MTU. You can use these metrics to troubleshoot network paths or verify that upstream DNS servers enforce specific size limits.
Summary
- MasterDnsVPN automatically discovers optimal MTU values at startup using binary-search probes against each configured resolver in
internal/client/mtu.go. - The process executes three stages: initialization (
RunInitialMTUTests), parallel probing (binarySearchMTU), and synchronization (applySyncedMTUState). - Upload probes validate size via echo probes containing 4-byte random codes, while download probes account for response overhead using
mtuDownResponseReserve. - The system selects the minimum viable upload and download MTU across all connections to ensure universal compatibility.
- Configure search bounds and parallelism via
MinUploadMTU,MaxUploadMTU,MinDownloadMTU,MaxDownloadMTU, andMTUTestParallelism. - Results optionally log to
MTU_SERVERS_FILE_NAMEusing the format defined ininternal/client/mtu_logging.go.
Frequently Asked Questions
How does MasterDnsVPN determine the optimal MTU size?
MasterDnsVPN uses a binary search algorithm implemented in internal/client/mtu.go (lines 143-191) to efficiently narrow down the maximum packet size. For each resolver, it tests progressively larger payloads until finding the threshold where responses fail, then selects the last successful size. The process runs separately for upload and download directions because network paths often exhibit asymmetric limitations.
Can I disable automatic MTU discovery and use static values?
While automatic discovery runs at startup, you can effectively control MTU behavior by setting narrow configuration bounds. Setting MinUploadMTU equal to MaxUploadMTU (and similarly for download) forces the binary search to select your preferred value. However, the client always executes the probe sequence to validate that the static size actually works on your network path.
What happens if MTU discovery fails for a specific resolver?
If a resolver fails to respond to probes or returns invalid echo codes, the summarizeValidMTUConnections function excludes that connection from the minimum calculation. The client only applies MTU values from successfully tested connections via applySyncedMTUState. Failed resolvers do not participate in the synced MTU determination, preventing a single broken path from degrading performance for working connections.
How does parallel testing affect MTU discovery accuracy?
The MTUTestParallelism setting (default 1) controls how many resolvers undergo simultaneous testing. Increasing this value speeds up discovery on high-latency networks but does not affect accuracy because each resolver's binary search operates independently. The system uses goroutines with proper context cancellation to ensure that increased parallelism does not cause probe cross-contamination or timeout conflicts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →