How UDP Works
The User Datagram Protocol (UDP) is defined in RFC 768 (1980) — one of the shortest and most enduring protocol specifications in internet history, at just three pages. UDP provides a minimal transport-layer service: it takes an application's data, wraps it in an 8-byte header, and sends it as a self-contained datagram. There is no handshake, no retransmission, no flow control, and no guarantee of delivery or ordering. That apparent simplicity is precisely what makes UDP the right choice for a wide class of applications.
The UDP Header
The entire UDP header is 8 bytes. No options, no extensions, no variable-length fields:
- Source Port (2 bytes) — identifies the sending socket. Optional for unidirectional flows; set to 0 if unused. For client sockets, the OS assigns an ephemeral port (typically 32768–60999 on Linux).
- Destination Port (2 bytes) — identifies the receiving service. Well-known ports: DNS 53, NTP 123, DHCP 67/68, QUIC 443, SNMP 161, SIP 5060.
- Length (2 bytes) — total size of the UDP datagram including the 8-byte header, in bytes. Minimum value 8. Maximum 65535, though IP fragmentation limits practical payload size.
- Checksum (2 bytes) — covers the UDP header, data, and a pseudo-header drawn from the IP layer (source IP, destination IP, protocol number, UDP length). In IPv4 the checksum is optional and may be set to zero; in IPv6 it is mandatory. The checksum uses one's-complement addition, the same scheme as TCP.
Connectionless Semantics
UDP has no concept of a connection. A sending application calls sendto() with a destination address and port, and the datagram is handed to IP immediately. There is no three-way handshake, no connection state, and no teardown sequence. The receiver needs no prior knowledge that a datagram is coming.
This has several concrete consequences:
- There is no per-flow state in the network or at endpoints. A UDP server handling 100,000 clients simultaneously maintains no per-client state unless the application layer implements it.
- Datagrams are independent. Two UDP datagrams sent from the same source to the same destination may arrive out of order, or one may not arrive at all. The application is responsible for handling this.
- There is no head-of-line blocking. A lost datagram does not stall subsequent datagrams, unlike TCP streams.
When UDP Beats TCP
The standard framing is "UDP for speed, TCP for reliability," but the real distinction is about who should handle loss, ordering, and flow control — the protocol layer or the application. UDP is the right choice when:
- Latency matters more than completeness — in a video call or online game, a stale frame is worse than a missing one. Retransmitting a 50ms-old audio packet would only make the problem worse; the application should simply skip it.
- The application has better loss handling — DNS can retry its own query faster than TCP's retransmit timer would fire. QUIC implements its own selective retransmission on top of UDP, with better algorithms than TCP's.
- Many short transactions — DNS lookups are typically one request/response pair. TCP's three-way handshake would double the round-trip overhead for every single lookup.
- Multicast or broadcast — TCP is unicast by design. DNS-SD, mDNS, DHCP, and network discovery protocols all use UDP because they need to address multiple receivers simultaneously.
Key Protocols Built on UDP
| Protocol | Port(s) | Why UDP |
|---|---|---|
| DNS | 53 | Single-RTT queries; application retries; UDP carries most queries, TCP for large responses/zone transfers |
| NTP | 123 | Single packet exchange; microsecond timestamps; TCP overhead and buffering would introduce jitter |
| QUIC | 443 | Implements its own reliable delivery, multiplexing, and congestion control on UDP to avoid OS TCP limitations and enable 0-RTT |
| DHCP | 67/68 | Client has no IP yet; must use broadcast before any unicast connection is possible |
| SIP / RTP | 5060/dynamic | Real-time voice/video; loss concealment preferable to retransmit stall |
| SNMP | 161/162 | Simple polling/trap model; lost poll is just retried |
| TFTP | 69 | Trivial file transfer for PXE boot; simplicity favored over features |
| WireGuard | 51820 | Stateless tunnel datagrams; outer UDP lets NAT and firewalls pass traffic naturally |
UDP and NAT
Network Address Translation (NAT) presents a challenge for UDP because there is no TCP connection state to anchor the translation mapping. NAT devices create UDP binding entries keyed on (source IP, source port, destination IP, destination port) when they see the first outbound datagram. The binding has a short timeout — typically 30 seconds on home routers, as little as 15 seconds on some carrier-grade NAT devices — because without a connection teardown, the NAT has no way to know the conversation is over.
Applications that need persistent UDP sessions through NAT (VoIP, online games, WireGuard) send keepalive datagrams at intervals shorter than the NAT timeout to prevent the binding from expiring. STUN (RFC 8489) and ICE (RFC 8445) are standardized protocols for discovering NAT bindings and enabling direct peer-to-peer UDP sessions through NAT — a process called NAT traversal.
UDP Amplification and Reflection Attacks
UDP's connectionless nature makes it trivially exploitable for DDoS amplification attacks. An attacker sends a small UDP request with a spoofed source IP (the victim's address) to a server. The server sends a large response to the victim. Common amplifiers:
| Protocol | Port | Amplification factor |
|---|---|---|
| Memcached | 11211 | Up to 51,000× |
| NTP (monlist) | 123 | Up to 556× |
| DNS (ANY query) | 53 | Up to 70× |
| SSDP (UPnP) | 1900 | Up to 30× |
| SNMP v2 | 161 | Up to 650× |
The fundamental defense is BCP 38 (RFC 2827) — network operators filtering outbound packets whose source IP does not belong to their address space, preventing IP spoofing at the source. Without BCP 38 compliance at the attacker's ISP, amplification attacks remain a persistent threat.
UDP-Lite and Partial Checksums
RFC 3828 defines UDP-Lite, a variant where the checksum can cover only part of the datagram. This is useful for media streaming where a corrupted video or audio payload is still useful — the application can do its own error concealment — but a corrupted header is fatal. UDP-Lite lets the checksum protect headers while letting corrupted payload bytes reach the application. It is used in some cellular broadcast (MBMS) and radio link protocols.
UDP Buffer Sizing and Dropped Datagrams
When the OS receives a UDP datagram, it places it in the socket's receive buffer. If the application is not reading fast enough and the buffer fills, incoming datagrams are silently dropped — the kernel simply discards them with no notification to the sender. This is fundamentally different from TCP, where a full receive window causes the sender to pause.
On Linux, the default UDP receive buffer size is 212,992 bytes (208 KB). For high-throughput UDP applications like video streaming or QUIC servers, this is often insufficient. The buffers can be increased:
sysctl -w net.core.rmem_max=26214400 sysctl -w net.core.wmem_max=26214400
QUIC implementations typically set socket buffer sizes explicitly at startup. Undersized buffers cause packet loss that looks identical to network loss, making it difficult to distinguish application-layer issues from network issues during debugging.
UDP Multicast and Broadcast
UDP supports both multicast and broadcast addressing, which TCP cannot. A UDP datagram sent to a multicast group address (224.0.0.0/4 for IPv4, ff00::/8 for IPv6) is delivered to all hosts that have joined that group on the receiving interface. A broadcast datagram (255.255.255.255 or a subnet broadcast like 192.168.1.255) reaches all hosts on a subnet.
This capability is used by:
- mDNS (Multicast DNS) — resolves local hostnames without a DNS server, used by Bonjour/Avahi, sent to 224.0.0.251 port 5353.
- SSDP (Simple Service Discovery Protocol) — UPnP device discovery via 239.255.255.250 port 1900. Also a major DDoS amplification source.
- PIM (Protocol Independent Multicast) — the routing protocol for internet multicast, which uses IGMP (IPv4) or MLD (IPv6) over UDP to manage group membership.
- RIP — the Routing Information Protocol uses UDP port 520 and sends routing updates to 224.0.0.9 (RIPv2).
QUIC: Rebuilding TCP on UDP
QUIC (RFC 9000) is the most significant UDP application in modern networking. It implements reliable, ordered, multiplexed delivery, TLS 1.3 encryption, and congestion control — everything TCP provides — as a user-space library running over UDP. The reason for using UDP rather than building a new transport protocol is pragmatic: UDP passes through NAT and firewalls without the special treatment that only TCP and ICMP have historically received, and it allows QUIC to evolve independently of the OS kernel's TCP stack.
HTTP/3 runs exclusively over QUIC. Major QUIC deployments include Google (all Google services), Cloudflare (all edge traffic), and Meta (internal and external). QUIC's 0-RTT connection resumption and connection migration (preserving a session when changing networks) are impossible to implement cleanly over TCP, making QUIC genuinely superior for mobile clients that change networks frequently.
Datagram Socket API
UDP sockets use the SOCK_DGRAM socket type. Unlike TCP's SOCK_STREAM, each sendmsg() or sendto() call produces exactly one UDP datagram, and each recvmsg() or recvfrom() returns exactly one datagram — message boundaries are preserved. Partial reads do not exist; if the application provides a buffer smaller than the datagram, the excess is discarded. This is the key semantic difference from TCP: UDP preserves message framing, TCP is a byte stream.
Connected UDP sockets (calling connect() on a SOCK_DGRAM socket) set a default destination address, enabling send()/recv() instead of sendto()/recvfrom(). This also enables the OS to return ICMP errors (like Port Unreachable) as socket errors on subsequent calls, which is not possible on unconnected UDP sockets.
UDP Fragmentation
A UDP datagram's payload can be up to 65,527 bytes (65,535 minus the 8-byte UDP header). But the IP layer limits packet size to the path MTU, typically 1500 bytes on Ethernet-connected paths. When an application sends a UDP datagram larger than the MTU, the IP layer fragments it (IPv4 only — IPv6 requires the application to handle fragmentation via the Fragment extension header).
IP fragmentation of UDP is problematic in several ways. Only the first fragment contains the UDP header with port numbers; stateful firewalls may not correctly reassemble or forward the subsequent fragments. NAT devices may drop non-first fragments. Firewalls with per-fragment inspection may apply different rules to fragments. In practice, applications that care about reliability and compatibility should keep UDP payloads below 1280 bytes to avoid fragmentation on any path — this is the minimum IPv6 MTU and works on essentially all internet paths.
GSO and GRO: Kernel Optimizations
For high-throughput UDP on Linux, the kernel provides two optimization mechanisms. Generic Segmentation Offload (GSO) allows the kernel to pass a large UDP "super-buffer" to the NIC driver, which then splits it into MTU-sized datagrams in hardware. Generic Receive Offload (GRO) does the reverse — the NIC or driver coalesces multiple incoming UDP datagrams into a single larger buffer before passing it to the kernel. Both reduce per-packet CPU overhead significantly, enabling 40+ Gbps UDP throughput on commodity hardware. QUIC implementations that use sendmmsg() and recvmmsg() system calls (which batch multiple send/receive operations) benefit from these optimizations automatically.
DNS and UDP: The Classic Example
DNS was designed to run over UDP for its query/response traffic and fall back to TCP for responses larger than 512 bytes (the original limit in RFC 1035). The EDNS0 extension (RFC 6891) allows DNS clients to announce a larger UDP payload size — typically 4096 bytes — telling resolvers they can send larger UDP responses without truncation. This matters for DNSSEC-signed responses, which can be several kilobytes.
The fallback to TCP (when a DNS response is truncated and has the TC bit set) adds latency: the client must establish a TCP connection, repeat the query, receive the full response, and tear down the connection. This is why resolver operators tune EDNS buffer sizes carefully and why DNS-over-TLS and DNS-over-HTTPS use TCP exclusively, accepting the connection overhead in exchange for encryption and consistency.
DNS over QUIC (RFC 9250, port 853) brings the low-latency benefits of UDP back to encrypted DNS. QUIC's 0-RTT resumption allows subsequent DNS queries to a previously contacted resolver to complete in a single round trip with full encryption, eliminating both the TCP and TLS handshake overhead while retaining the reliability guarantees that recursive resolvers need.
Explore It Live
DNS over UDP is the most common protocol you can observe through routing data. DNS queries for domains like google.com ultimately resolve to prefixes you can look up here:
- 8.8.8.8 — Google's public DNS resolver, reachable via UDP port 53
- 1.1.1.1 — Cloudflare's DNS resolver; also serves DNS-over-QUIC (UDP 853)
- AS13335 — Cloudflare's network, which handles billions of UDP DNS queries daily
The BGP looking glass shows the routing paths to these UDP-heavy services across the global internet.