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 bits 0-15 (2 bytes) Destination Port bits 16-31 (2 bytes) Length bits 32-47 (2 bytes) Checksum bits 48-63 (2 bytes) Data (variable length) Length field includes 8-byte header · max datagram = 65535 bytes total

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:

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:

Key Protocols Built on UDP

ProtocolPort(s)Why UDP
DNS53Single-RTT queries; application retries; UDP carries most queries, TCP for large responses/zone transfers
NTP123Single packet exchange; microsecond timestamps; TCP overhead and buffering would introduce jitter
QUIC443Implements its own reliable delivery, multiplexing, and congestion control on UDP to avoid OS TCP limitations and enable 0-RTT
DHCP67/68Client has no IP yet; must use broadcast before any unicast connection is possible
SIP / RTP5060/dynamicReal-time voice/video; loss concealment preferable to retransmit stall
SNMP161/162Simple polling/trap model; lost poll is just retried
TFTP69Trivial file transfer for PXE boot; simplicity favored over features
WireGuard51820Stateless 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:

ProtocolPortAmplification factor
Memcached11211Up to 51,000×
NTP (monlist)123Up to 556×
DNS (ANY query)53Up to 70×
SSDP (UPnP)1900Up to 30×
SNMP v2161Up 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:

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.

UDP vs TCP: Latency Profile UDP (e.g. DNS query) Client → sendto() → datagram out Server → recvfrom() → sendto() Client → recvfrom() → done 1 RTT total TCP (e.g. HTTPS) SYN → SYN-ACK → ACK (1 RTT) TLS handshake (1-2 RTT) Request → Response 3+ RTT total before data

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:

The BGP looking glass shows the routing paths to these UDP-heavy services across the global internet.

See BGP routing data in real time

Open Looking Glass
← Previous How Zigbee, Thread, and Matter Work: IoT Mesh Networking Protocols
More Articles
What is DNS? The Internet's Phone Book
What is an IP Address?
IPv4 vs IPv6: What's the Difference?
What is a Network Prefix (CIDR)?
How Does Traceroute Work?
What is a CDN? Content Delivery Networks Explained