MasterDnsVPN Packet Packing and Batch Processing Internals: How Control Packets Are Bundled
MasterDnsVPN reduces UDP overhead by concatenating multiple control packets into a single PACKET_PACKED_CONTROL_BLOCKS datagram, processing each 7-byte block individually on the receiving end.
MasterDnsVPN implements an efficient packet packing mechanism that bundles multiple small control packets into a single UDP datagram. This optimization targets the inherent inefficiency of sending individual acknowledgments and control messages, significantly reducing bandwidth consumption and per-packet processing overhead according to the masterking32/MasterDnsVPN source code.
Why Pack Control Packets?
Control packets in MasterDnsVPN carry no payload—they include ACK/NACK confirmations, stream-control messages, and DNS acknowledgments. Sending each of these small messages individually wastes bandwidth and increases per-packet latency. By concatenating their metadata into fixed-size blocks, the protocol transmits up to dozens of acknowledgments in a single UDP packet.
The packing mechanism centers on the special packet type PACKET_PACKED_CONTROL_BLOCKS (value 0x13), defined in internal/enums/packet_identity.go. This packet type carries a payload consisting of one or more packed 7-byte blocks containing the original packet metadata.
Core Data Structures and Constants
The packing system relies on several key constants and structures defined across the internal/vpnproto package:
PackedControlBlockSize: Fixed at 7 bytes, defined ininternal/vpnproto/packing.go. Each block contains the packet type, stream ID, sequence number, fragment ID, and total fragments.PACKET_PACKED_CONTROL_BLOCKS: The packet type constant (0x13) that identifies packed control payloads.BuildOptions: Parameters used byinternal/vpnproto/builder.goto assemble raw VPN packets with headers and optional payloads.maxPackedBlocks: Runtime limit calculated byCalculateMaxPackedBlocksininternal/vpnproto/utils.go, determining how many blocks fit within the configured MTU.
Client-Side Packet Packing Implementation
The client-side packing logic resides primarily in internal/client/dispatcher.go, where the dispatcher coordinates packet transmission.
Identifying Packable Packets
Before packing, the system determines if a packet qualifies for aggregation. The function vpnproto.IsPackableControlPacket(pktType, payloadLen) in internal/vpnproto/packing.go returns true only for specific control types:
- ACK/NACK packets
- SOCKS5 control messages
- DNS acknowledgments
Packets with payloads or non-control types are excluded from the packing process.
Collecting and Serializing Blocks
The dispatcher iterates over the selected stream's TX queue (and optionally other streams and the orphan queue), pulling packable control packets until maxPackedBlocks is reached. Each block is serialized using AppendPackedControlBlock:
payload = VpnProto.AppendPackedControlBlock(payload,
item.PacketType, selectedStreamID,
item.SequenceNum, item.FragmentID, item.TotalFragments)
This function appends exactly 7 bytes per block to the payload buffer.
Building the Final Datagram
If multiple blocks are collected, the dispatcher sets the outer packet type to PACKET_PACKED_CONTROL_BLOCKS and clears stream-specific fields. The packet is then constructed using vpnproto.BuildOptions and passed to the transmission planner. Single packets are transmitted normally without the packing wrapper.
Server-Side Batch Processing and Unpacking
Receiving Packed Blocks
When a PACKET_PACKED_CONTROL_BLOCKS packet arrives, internal/udpserver/server_postsession.go routes it to handlePackedControlBlocksRequest. This handler uses ForEachPackedControlBlock to iterate through the payload:
VpnProto.ForEachPackedControlBlock(vpnPacket.Payload, func(packetType uint8,
streamID uint16, sequenceNum uint16, fragmentID uint8, totalFragments uint8) bool {
block := VpnProto.Packet{
SessionID: vpnPacket.SessionID,
SessionCookie: vpnPacket.SessionCookie,
PacketType: packetType,
StreamID: streamID,
HasStreamID: true,
SequenceNum: sequenceNum,
HasSequenceNum: true,
FragmentID: fragmentID,
TotalFragments: totalFragments,
}
// Process inner packet...
return true
})
ForEachPackedControlBlock walks the payload 7 bytes at a time, invoking the callback for each block.
Individual Block Processing
Each unpacked block is processed as a standard inbound packet through preprocessInboundPacket (for duplicate detection) and dispatchPostSessionPacket (for routing to ACK or stream-control handlers). Nested packing is not supported—if a packed block contains another PACKET_PACKED_CONTROL_BLOCKS type, it is ignored.
Creating Server-Side Batches
The server builds packed packets in internal/udpserver/server_session.go via the packControlBlocks function:
- Start with the first control packet and append additional blocks from active streams or the orphan queue
- Respect the
record.MaxPackedBlockslimit to avoid fragmentation - Use
AppendPackedControlBlockto serialize each component - Set the final packet type to
PACKET_PACKED_CONTROL_BLOCKS
Maximum Block Calculations and MTU Constraints
The function CalculateMaxPackedBlocks in internal/vpnproto/utils.go determines the optimal number of blocks per packet:
effectiveSize := (mtu * percent) / 100
count := max(min(max(effectiveSize / vpnproto.PackedControlBlockSize, 1), absoluteMax), 1)
This calculation ensures packed packets fit comfortably within the MTU while maximizing density. The client initializes c.maxPackedBlocks using this function when creating a new Client instance.
Reliability and Duplicate Transmission
Both client and server optionally repeat packed blocks to improve reliability over unreliable UDP transport. The server stores the last packed block in record.LastPackedControlBlock with a counter LastPackedControlBlockRemaining, governed by the PacketBlockControlDuplication configuration. The client tracks retransmission counts via runtimePacketDuplicationCount to prevent excessive duplication while maintaining delivery guarantees.
Summary
- 7-byte blocks: Each control packet packs into a fixed-size block containing type, stream ID, sequence number, and fragment metadata.
- Type 0x13:
PACKET_PACKED_CONTROL_BLOCKSidentifies aggregated control packets. - Client aggregation:
client/dispatcher.gocollects packable packets usingIsPackableControlPacketandAppendPackedControlBlock. - Server unpacking:
server_postsession.gousesForEachPackedControlBlockto iterate and process individual blocks. - MTU awareness:
CalculateMaxPackedBlocksensures optimal packing density without fragmentation. - Nested protection: The protocol explicitly ignores nested packed packets to prevent parsing errors.
Frequently Asked Questions
What is the size of each packed control block?
Each packed control block is exactly 7 bytes, defined as the constant PackedControlBlockSize in internal/vpnproto/packing.go. This compact size includes the packet type, stream ID, sequence number, fragment ID, and total fragments count, allowing efficient aggregation of multiple control messages.
How does MasterDnsVPN prevent nested packing?
The server explicitly checks for and ignores any packed blocks that contain the PACKET_PACKED_CONTROL_BLOCKS type (0x13). This protection, implemented in handlePackedControlBlocksRequest within internal/udpserver/server_postsession.go, ensures that the unpacking process only processes one level of aggregation and avoids recursive parsing complexity.
What happens if the packed packet would exceed the MTU?
The CalculateMaxPackedBlocks function in internal/vpnproto/utils.go pre-calculates the maximum number of 7-byte blocks that fit within a percentage of the MTU. Both client and server respect this limit (maxPackedBlocks or record.MaxPackedBlocks), ensuring packed payloads never exceed safe transmission sizes and preventing IP fragmentation.
Can packed packets contain data payloads or only control packets?
Packed packets only contain control packets. The IsPackableControlPacket function explicitly checks that the payload length is zero and the packet type is a recognized control type (ACK, NACK, SOCKS5 control, etc.). Data packets with actual payloads are transmitted separately and are never bundled into PACKET_PACKED_CONTROL_BLOCKS datagrams.
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 →