UDP
Connectionless, fast, no guarantees
What UDP Is (and Isn't)
UDP (User Datagram Protocol) is the other major Layer 4 transport protocol. Where TCP provides a reliable, ordered byte stream, UDP provides almost nothing on top of raw IP — and that's the point.
What UDP Does NOT Provide
- No connection establishment — no handshake, no state machine, no teardown
- No reliability — packets can be lost, duplicated, or corrupted (beyond checksum)
- No ordering — packets can arrive in any order
- No retransmission — if a packet is lost, UDP doesn't know or care
- No flow control — sender can blast data as fast as it wants
- No congestion control — UDP will happily contribute to network congestion
What UDP DOES Provide
- Multiplexing via ports — multiple applications can share an IP address
- Integrity check — optional checksum (optional in IPv4, mandatory in IPv6)
- Message boundaries — unlike TCP's byte stream, each
sendto()maps to exactly one datagram. The receiver gets complete messages, not a stream.
Note
Message boundaries matter: TCP is a byte stream — a send(1000 bytes) followed by send(500 bytes) might be received as a single 1500-byte read. UDP preserves message boundaries — each sendto() produces exactly one datagram that the receiver gets as a complete unit via recvfrom().
UDP Header
The UDP header is 8 bytes — that's it. Compare this to TCP's minimum 20 bytes (and typically 32 bytes with options). UDP's simplicity is its greatest feature.
Header Fields
| Field | Notes |
|---|---|
Source Port | Optional (can be 0 if no reply expected) |
Destination Port | Required — identifies the target application |
Length | Total datagram size (header + payload). Min = 8 (empty payload). Max = 65,535 (but practically limited by IP MTU) |
Checksum | Covers pseudo-header + header + payload. Optional in IPv4 (0 = no checksum), mandatory in IPv6. |
TCP vs UDP Header Comparison
- Source Port (16 bits)
- Destination Port (16 bits)
- Sequence Number (32 bits)
- Acknowledgment Number (32 bits)
- Data Offset (4 bits)
- Reserved (3 bits)
- 9 Flags (9 bits)
- Window Size (16 bits)
- Checksum (16 bits)
- Urgent Pointer (16 bits)
- Options (0-320 bits)
= 160+ bits minimum = 20+ bytes
- Source Port (16 bits)
- Destination Port (16 bits)
- Length (16 bits)
- Checksum (16 bits)
= 64 bits = 8 bytes
No sequence numbers. No acknowledgments. No flags. No window. No options. No state.
| Property | TCP | UDP |
|---|---|---|
| Connection | Connection-oriented (3-way handshake) | Connectionless |
| Reliability | Guaranteed delivery with retransmission | Best effort — fire and forget |
| Ordering | Guaranteed in-order delivery | No ordering guarantees |
| Flow control | Sliding window (rwnd) | None |
| Congestion control | cwnd, slow start, CUBIC/BBR | None (application must self-regulate) |
| Message boundaries | Byte stream (no boundaries) | Datagram (preserved boundaries) |
| Header overhead | 20-60 bytes | 8 bytes |
| Latency to first data | 1.5 RTT (handshake + data) | 0 RTT (send immediately) |
| Use case | HTTP, SSH, databases, file transfer | DNS, video/audio, gaming, VPN tunnels |
When UDP Wins
DNS Lookups
- Tiny request (~50 bytes), tiny response (~100-500 bytes)
- TCP handshake would triple the latency (1 RTT vs 3 RTT)
- If the response is lost, the client just retries
- Falls back to TCP for responses > 512 bytes (or uses EDNS0 for larger UDP)
Video / Audio Streaming
- Late data is useless — a retransmitted video frame that arrives 500ms late causes a stutter worse than just skipping it
- Tolerate packet loss gracefully (codec interpolation, FEC)
- RTP (Real-time Transport Protocol) runs over UDP
- WebRTC uses UDP for media streams
Gaming
- Player position updates are sent 30-60 times per second
- A lost update is immediately superseded by the next one
- TCP retransmission would cause a latency spike (head-of-line blocking)
- Games implement their own reliability layer for critical events (damage, kills) while letting position updates be unreliable
VPN Tunnels
- WireGuard uses UDP — its entire protocol is UDP-based
- Avoids TCP-in-TCP meltdown: if you tunnel TCP traffic inside a TCP VPN, both layers retransmit on loss, causing exponential backoff stacking
- OpenVPN also supports UDP mode (recommended over TCP mode)
- IPsec ESP can run directly over IP or be wrapped in UDP (NAT traversal)
DHCP
- The client doesn't have an IP address yet — it can't establish a TCP connection
- Uses broadcast/multicast on UDP ports 67 (server) and 68 (client)
- DISCOVER → OFFER → REQUEST → ACK, all over UDP
Warning
TCP-in-TCP meltdown explained: When TCP runs inside a TCP tunnel, packet loss triggers retransmission at both layers. The inner TCP retransmits, increasing the data volume. The outer TCP also retransmits. Both reduce their congestion windows. The result: throughput collapses far worse than a single layer of TCP would. This is why WireGuard, IPsec, and well-configured OpenVPN all use UDP as the outer transport.
Reliable-UDP Protocols
QUIC (HTTP/3)
QUIC is the most important networking protocol development in the last decade. It's a reliable, encrypted transport protocol built on top of UDP, designed by Google and standardized as RFC 9000.
QUIC Architecture
Why QUIC Over UDP Instead of Fixing TCP?
| Problem with TCP | QUIC's Solution |
|---|---|
| Ossification: Middleboxes (firewalls, NATs, load balancers) inspect and sometimes modify TCP headers. Deploying TCP extensions is nearly impossible. | QUIC encrypts everything except the connection ID. Middleboxes can't inspect or modify what they can't read. |
| Head-of-line blocking: In HTTP/2 over TCP, a single lost packet blocks ALL streams (TCP guarantees in-order delivery of the byte stream). | QUIC provides independent streams — a lost packet only blocks the affected stream. Other streams continue flowing. |
| Handshake latency: TCP handshake (1 RTT) + TLS handshake (1-2 RTT) = 2-3 RTT before data. | QUIC integrates TLS 1.3 into its handshake: 1 RTT for new connections, 0-RTT for resumed connections. |
| Connection migration: TCP connections are tied to the 4-tuple. WiFi → cellular = new connection. | QUIC uses Connection IDs, not IP:port tuples. Connections survive network changes (phone switches from WiFi to LTE). |
| Kernel dependency: TCP is implemented in the OS kernel. Updates require kernel upgrades across the fleet. | QUIC runs in userspace. Deploy a new version by updating the application binary. |
Tip
Adoption status: QUIC / HTTP/3 is used by Google (YouTube, Search, Gmail), Cloudflare, Meta, and most CDNs. Chrome, Firefox, Safari, and Edge all support it. If you run a web-facing service behind Cloudflare or a major CDN, your users are likely already using QUIC.
UDP and NAT
NAT traversal for UDP is conceptually simpler than for TCP because there's no connection state to track.
How UDP NAT Traversal Works
- When an internal host sends a UDP packet out, the NAT creates a mapping:
(internal IP:port) → (external IP:port) - Replies from the external destination to that external IP:port are forwarded back to the internal host
- The mapping times out after an idle period (typically 30-120 seconds for UDP, varies by device)
- STUN (Session Traversal Utilities for NAT): allows a host to discover its public IP:port mapping by querying an external server
- TURN (Traversal Using Relays around NAT): relay server for when direct P2P fails (symmetric NAT)
- UDP hole punching: both peers send packets to each other's NAT-mapped addresses simultaneously, creating bidirectional mappings
Note
NAT keepalive: UDP NAT mappings expire on idle (often 30s). Long-lived UDP connections (VPN, VoIP) must send periodic keepalive packets to prevent the NAT mapping from expiring. WireGuard has a PersistentKeepalive setting specifically for this (commonly set to 25 seconds).
UDP Checksum
- UDP checksum is optional
- A checksum value of 0 means "no checksum computed"
- IPv4 has its own header checksum, but it only covers the IP header, not the payload
- Without the UDP checksum, bit flips in the payload go undetected (relying on link-layer CRC, which isn't end-to-end)
- UDP checksum is mandatory
- IPv6 removed the IP header checksum (to speed up router processing)
- Without a mandatory UDP checksum, there would be no integrity check at all above the link layer
- Exception: RFC 6936 allows checksum-zero for IPv6 tunneling protocols
Note
In practice: All modern UDP implementations compute the checksum. The "optional" nature in IPv4 is a historical artifact. Disabling it would be dangerous — intermediate routers can corrupt data in ways that link-layer CRC doesn't catch (silent corruption from buggy firmware, bit flips in router memory, etc.).
Practical Considerations
UDP Datagram Size Limits
| Limit | Value | Why It Matters |
|---|---|---|
| Theoretical max | 65,507 bytes (65,535 - 8 UDP header - 20 IP header) | The Length field is 16 bits |
| Typical safe size | ~1,472 bytes (1500 MTU - 20 IP - 8 UDP) | Avoids IP fragmentation on Ethernet |
| Internet safe size | ~1,200 bytes | Avoids fragmentation across VPNs, tunnels, and paths with smaller MTU |
Warning
IP fragmentation is dangerous for UDP: If a UDP datagram exceeds the path MTU, IP will fragment it. If any fragment is lost, the entire datagram is lost (UDP has no retransmission). This effectively amplifies the packet loss rate. QUIC deliberately keeps its packets under the MTU to avoid this.
# Test path MTU to a destination
$ tracepath -n 10.0.0.5
1?: [LOCALHOST] pmtu 1500
1: 10.0.0.1 0.234ms
2: 10.0.0.5 1.023ms reached
Resume: pmtu 1500 hops 2 back 2
# Send a UDP packet with specific size (useful for testing)
$ echo "test payload" | socat - UDP4:10.0.0.5:9999