Skip to content

UDP Deep Dive

UDP (User Datagram Protocol, RFC 768) is the simplest transport-layer protocol in the TCP/IP suite: An 8-byte header, no handshake, no state, no guarantees. Despite (or because of) this simplicity, UDP is the foundation for some of the most critical and high-performance protocols on the Internet. DNS, DHCP, NTP, SNMP, streaming media, gaming, VPNs, and QUIC all ride on UDP.

This document dissects UDP internals, explains when and why UDP is the right choice, covers Broadcast and multicast, and examines the reliability patterns that UDP-based protocols implement at The application layer.

The UDP header is exactly 8 bytes — the minimum of any transport protocol:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Length | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data (variable length) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FieldBitsDescription
Source Port16Optional. Identifies the sender. Zero means “not specified.”
Destination Port16Required. Identifies the intended receiver.
Length16Total UDP datagram length: header (8) + data. Minimum 8. Maximum 65535.
Checksum16Coverage includes pseudo-header + UDP header + data. Zero = “no check” (IPv4 only).

The source port is optional. If the sender does not need a reply, it can set the source port to Zero. This is rare in practice because most applications need responses, and the source port is how The receiver knows where to send them.

When the source port is non-zero, it is an ephemeral port chosen by the kernel from the Range defined by net.ipv4.ip_local_port_range (default: 32768-60999 on Linux).

The Length field is 16 bits, so the maximum UDP datagram is 65,535 bytes. Subtracting the 8-byte Header gives a maximum payload of 65,527 bytes. However, IP fragmentation limits the practical Maximum to the path MTU minus IP and UDP headers ( 1472 bytes over standard Ethernet).

Terminal window
# View current UDP buffer sizes
sysctl net.core.rmem_max
sysctl net.core.rmem_default
sysctl net.core.wmem_max
sysctl net.core.wmem_default
# Increase UDP receive buffer for high-throughput applications
sysctl -w net.core.rmem_max=16777216

The UDP checksum covers three things:

  1. Pseudo-header: Source IP, destination IP, protocol number (17), and UDP length
  2. UDP header: All four fields
  3. Data payload: Everything after the header

The checksum is the ones-complement of the ones-complement sum of all 16-bit words. If the data Length is odd, a zero byte is appended for computation purposes only.

IPv4 pseudo-header:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Zero | Protocol | UDP Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

IPv6 pseudo-header:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Source Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ +
| |
+ Destination Address +
| |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| UDP Length (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Next Header (8 bits) | Zero
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Key differences: IPv6 pseudo-header uses 32-bit length (instead of 16-bit), 128-bit addresses (instead of 32-bit), and “Next Header” field (instead of Protocol). The IPv6 pseudo-header is 40 Bytes vs 12 bytes for IPv4.

In IPv4, a checksum of zero means “no checksum computed.” The sender explicitly sets the checksum Field to zero to indicate this. The receiver must accept datagrams with a zero checksum without Verification.

In IPv6, the checksum is mandatory. A zero checksum in IPv6 UDP is not valid. This was a Deliberate design decision in IPv6 because the 128-bit addresses make the pseudo-header much larger, And the probability of an undetected corruption affecting the pseudo-header is non-trivial.

UDP-Lite modifies the checksum to cover only a partial payload. The “Checksum Coverage” field Replaces the Length field and specifies how many bytes of the payload are covered by the checksum. Applications that tolerate bit errors in the payload (voice, video) can use UDP-Lite to reduce the Probability of a datagram being discarded due to a checksum failure in non-critical data.

Terminal window
# Check if UDP-Lite is supported
grep UDP-LITE /proc/net/protocols

DNS uses UDP for queries and responses under 512 bytes (originally; EDNS0 extends this). If the Response exceeds the limit, the server sets the TC (Truncation) bit, and the client retries over TCP.

Why UDP: DNS queries are small, a single request-response pair, and the overhead of TCP”s three-way Handshake (3 packets) would exceed the query itself (1 packet). UDP gets the answer in one round Trip instead of three.

DHCP uses UDP because the client does not yet have an IP address and cannot establish a TCP Connection. The client sends from 0.0.0.0:68 to 255.255.255.255:67 (broadcast).

NTP uses UDP because time synchronization requires low-latency, lightweight exchanges. A single NTP Packet is 48 bytes. TCP’s handshake would add 100ms+ of latency on a WAN link, directly degrading Time accuracy.

SNMP uses UDP because management queries are small and periodic. A manager sends a GET request, the Agent responds with a GET-RESPONSE. No persistent connection is needed.

RTP (Real-time Transport Protocol, RFC 3550) uses UDP because:

  • Latency is more important than reliability. A dropped video frame is acceptable; a delayed frame is not.
  • Retransmission is pointless for real-time data. By the time a lost packet is retransmitted, its playback window has passed.
  • Application-level forward error correction (FEC) and adaptive bitrate are more appropriate than TCP’s reliability.

Multiplayer games use UDP because:

  • Game state updates are small and frequent (20-60 ticks per second)
  • Old state updates are irrelevant (you want the latest position, not the position from 50ms ago)
  • TCP’s head-of-line blocking means one lost packet delays all subsequent packets
  • Application-level interpolation and prediction handle packet loss gracefully

QUIC (RFC 9000) runs over UDP because:

  • Bypassing middlebox ossification. Deploying a new transport protocol at the IP layer is effectively impossible due to firewalls and NATs that only understand TCP and UDP. Running QUIC over UDP means it traverses existing infrastructure.
  • Connection migration. QUIC’s connection IDs allow a connection to survive IP address changes (WiFi to cellular), which is impossible with TCP’s 4-tuple identification.
  • 0-RTT connection establishment. QUIC combines the transport handshake with TLS 1.3, reducing connection setup to a single round trip (or zero for repeat connections).

Limited broadcast is sent to all hosts on the local network segment. It is never forwarded by Routers. Used by DHCP clients that do not yet know their network address.

Terminal window
# Send a limited broadcast
echo "test" | socat - UDP-DATAGRAM:255.255.255.255:9000,broadcast
# Capture broadcast traffic
tcpdump -i eth0 'dst 255.255.255.255'

Directed broadcast is sent to the broadcast address of a specific subnet (e.g., 192.168.1.255/24). Routers may forward directed broadcasts (though this is disabled by default, RFC 2644).

Terminal window
# Directed broadcast example
# 192.168.1.255 is the broadcast address for 192.168.1.0/24
ping -b 192.168.1.255

Every subnet has a broadcast address: the last address in the subnet (all host bits set to 1). For 10.0.0.0/24The broadcast is 10.0.0.255. For 10.0.0.0/23The broadcast is 10.0.1.255.