TCP, UDP, ss, netstat, and tcpdump: A Layered Network Debugging Guide
Diagnose connection failures by separating DNS, routing, transport, listening sockets, and application protocol behavior.
On this page
Key takeaways
- TCP provides a connection-oriented byte stream; UDP sends datagrams without transport-level delivery guarantees.
- A listening socket, a reachable port, and a healthy application protocol are separate facts.
- Use ss for current socket state, netstat when available, and tcpdump to inspect packets at an interface.
- Packet captures may contain sensitive data; limit scope, duration, and permissions.
Work from the symptom outward
“Connection failed” is not a diagnosis. Identify the source host, destination name and resolved address, port, protocol, timestamp, and exact client error. Then separate name resolution, routing, firewall policy, transport establishment, TLS negotiation, and application response. A successful ping does not prove a TCP service port is reachable, and an open TCP port does not prove the application is healthy.
TCP and UDP are different contracts
TCP establishes a connection and provides an ordered byte stream with retransmission and flow control. It does not preserve application message boundaries; clients must frame their messages. UDP sends datagrams and leaves delivery, ordering, and retry policy to the application. A UDP service may appear silent when filtered, overloaded, or simply not configured to answer the probe.
Use a protocol-appropriate check. nc -vz host port can test a TCP connection, but is not a general UDP health check. For a UDP protocol, send a valid request and observe the expected response, or capture traffic at both endpoints.
Inspect local socket state
On modern Linux, ss -lntup shows listening TCP/UDP sockets and owning processes when permissions allow. ss -tan state established can help inspect established connections. netstat -lntup is familiar on older systems but may not be installed by default; on Linux it is commonly supplied by the net-tools package. macOS has a different netstat implementation and options, so check man netstat locally.
A process listening only on 127.0.0.1 is not reachable from other hosts through the machine's external address. Confirm bind address, port, namespace/container mapping, and service endpoint before changing firewall rules.
Capture packets carefully
A short, narrow capture is often enough:
sudo tcpdump -ni any 'host 192.0.2.20 and port 443' -c 100
-n avoids reverse DNS lookups, -i selects an interface, and the filter limits traffic. Observe whether a SYN leaves, whether a SYN-ACK returns, and whether resets or retransmissions occur. Capturing on both client and server sides can distinguish network loss from local policy. TLS payloads are encrypted, but packet metadata and unencrypted protocols may still expose sensitive information.
Common patterns
- SYN leaves, no response: routing, firewall, security group, or destination availability may be involved.
- Immediate reset: a host responded but no service is listening on that address/port, or a middlebox actively rejected it.
- TCP establishes, then TLS fails: inspect certificates, protocol versions, SNI, and clock skew.
- TCP works locally but not remotely: check bind address, host firewall, container port publishing, and network policy.
- UDP request leaves with no reply: confirm the request is valid for the protocol and capture at the receiver before concluding the path is blocked.
Safe diagnostic sequence
Resolve the name, inspect the route, verify the expected listener, test the transport, then test the actual application protocol. Capture only what you need and remove packet files according to the data policy. Do not open broad firewall rules as a diagnostic shortcut; use a temporary, scoped change only when authorized and remove it immediately after the test.