Ports, sockets and UDP
UDP
Independent datagrams with ports and nothing else: no connection, no acknowledgement, no retries.
A sender's success only means the datagram left. A closed port may answer with ICMP port unreachable. DNS, DHCP, VoIP and WireGuard use UDP: they prefer a small gap, or their own recovery, to TCP's waiting.
How UDP works, step by step
UDP (RFC 768) adds almost nothing to IP: ports, so a datagram reaches the right program, and a checksum. Its header is 8 bytes, four fields of 16 bits:
| Field | Meaning |
|---|---|
| Source port | where replies should go; may be 0 if none are wanted |
| Destination port | the program on the receiving machine: 53 for DNS, 67 and 68 for DHCP, 123 for NTP |
| Length | header plus data, in bytes |
| Checksum | covers header, data and a pseudo-header of the IP addresses; optional in IPv4, required in IPv6 |
Sending a DNS question shows the whole protocol:
- The program writes one message to a UDP socket. The kernel picks an ephemeral source port if the program did not bind one.
- The kernel wraps it in a UDP header and an IP packet and sends it. No handshake comes first.
- The receiving kernel checks the checksum, looks up a socket bound to the destination port and queues the datagram, whole, for that program. One write, one read: message boundaries survive, unlike TCP's byte stream.
- The program answers, to the source address and port it read.
Nothing else happens. No acknowledgement, no retransmission, no ordering, no rate control. If a datagram is lost, the program finds out only by not getting an answer, and decides itself whether to ask again: a DNS resolver retries after a timeout, a voice call plays a tiny gap and moves on.
A datagram to a port where nothing listens is answered by the receiving kernel with an ICMP port unreachable, unless a firewall drops it. The sender's program only learns of that if its socket is connected and it reads again.
What it looks like on a Linux machine
In the TCP and UDP lab the server runs an echo service on port 7, over TCP and UDP. ss
shows the UDP socket as UNCONN, not LISTEN: there are no connections to accept, only datagrams to read.
$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 *:7 *:* users:(("socat",pid=8,fd=5))
tcp LISTEN 0 5 *:7 *:* users:(("socat",pid=7,fd=5))
The laptop sends hello by UDP, then to port 9, where nothing listens:
$ tcpdump -nn -i eth0 udp or icmp
IP 10.0.1.10.48438 > 10.0.2.10.7: UDP, length 6
IP 10.0.2.10.7 > 10.0.1.10.48438: UDP, length 6
IP 10.0.1.10.52001 > 10.0.2.10.9: UDP, length 6
IP 10.0.2.10 > 10.0.1.10: ICMP 10.0.2.10 udp port 9 unreachable, length 42
Two packets for the echo, where TCP needed ten. And nc -u exits with 0 for port 9 too: sending worked, and that
is all UDP ever promised.
TCP vs UDP
| UDP | TCP | |
|---|---|---|
| Setup | None | Three-way handshake |
| Reliability | None; the program retries if it cares | Acknowledgements and retransmission |
| Order | Not kept | Kept |
| Message boundaries | Kept: one send, one datagram | Lost: a stream of bytes |
| Header | 8 bytes | 20 to 60 bytes |
| One to many | Broadcast and multicast work | One peer per connection |
| Typical uses | DNS, DHCP, NTP, SNMP, VoIP, games, QUIC | Web, SSH, mail, databases |
UDP is the right choice when a late answer is worthless, when one packet is the whole conversation, or when the program builds its own reliability, as QUIC does for HTTP/3.
What goes wrong, and how you see it
Silence. A UDP scan cannot tell an open port that does not reply from a firewall that drops: both look the
same. Only an ICMP port unreachable proves a port closed. Loss under load. A receiver too slow to read lets its
socket buffer fill, and the kernel drops what arrives: netstat -su counts receive buffer errors. Big
datagrams. Anything larger than the path MTU is fragmented, and losing one fragment loses the whole datagram;
that is why DNS software now offers 1232 bytes over UDP and moves larger answers to TCP. Spoofing. No handshake means the source address is
not checked, which is what DNS amplification exploits.
Questions people ask
Why use UDP if it is unreliable? Because waiting is worse for some traffic. A resent voice packet arrives too late to play, and a one-packet DNS question is cheaper to repeat than to open a connection for.
Is UDP connectionless? Yes. A program may connect() a UDP socket, but that only fixes the peer address in the
kernel; nothing is sent.
Does UDP have flow control? No. Protocols built on it, such as QUIC, add their own.