Linux Network Diagnosis Cheat Sheet
Walk a network fault layer by layer — reachability, routing, ports, DNS, TLS and packet capture — and prove whether latency lives in the network or the application.
Work bottom-up
Test the lowest layer first. Every minute spent debugging TLS on a host with no route is wasted.
| Layer | Question | Command |
|---|---|---|
| Link | Is the interface up? | ip link |
| Network | Can packets reach it? | ping, mtr |
| Transport | Is the port open? | nc -zv, ss |
| Session | Does TLS negotiate? | openssl s_client |
| Application | Does the app answer? | curl -v |
Interfaces and addresses
ip -br addr # brief: name, state, addresses
ip link show # link state and MTU
ip -s link show IFACE # counters: errors, drops, overruns
ethtool IFACE # negotiated speed and duplex
Non-zero errors or dropped in ip -s link points at cabling, a driver, or a
saturated NIC ring buffer — not at your application.
Reachability and path
ping -c 5 HOST # ICMP reachability and RTT
ping -c 5 -M do -s 1472 HOST # test 1500-byte MTU without fragmentation
mtr -r -c 20 HOST # combines traceroute + per-hop loss
traceroute -T -p 443 HOST # TCP traceroute — ICMP is often filtered
Loss at an intermediate hop is usually not a fault. Routers deprioritise generating ICMP replies. Only loss that persists to the final hop matters.
If ping works but a large payload hangs, suspect MTU. The -M do -s test above
fails with “message too long” when the path MTU is smaller than you assume — a
classic cause of hangs on VPNs and overlay networks.
Ports and sockets
nc -zv HOST PORT # is the port accepting TCP?
nc -zv -w 3 HOST PORT # with timeout
ss -tulpn # listening TCP/UDP sockets with process
ss -tan state established # established connections
ss -tan state time-wait | wc -l
ss -tn dst HOST # connections to a specific host
ss -i # per-socket rtt, cwnd, retransmits
ss -i shows retransmissions per socket — the most direct evidence that packet
loss, not the application, is causing slowness.
sudo lsof -i :PORT # which process owns a local port
sudo fuser -n tcp PORT
Connection refused vs timeout
| Symptom | Meaning |
|---|---|
Connection refused | Reached the host; nothing is listening. RST returned |
Connection timed out | Packets dropped silently — firewall or security group |
No route to host | Local routing or ARP failure |
Refused means you got through. Timeout means you did not.
DNS
dig HOST # full answer
dig +short HOST
dig @1.1.1.1 HOST # bypass the local resolver
dig +trace HOST # full delegation chain from the root
dig -x 10.0.0.5 # reverse lookup
resolvectl status # systemd-resolved: what is actually configured
cat /etc/resolv.conf
Compare a direct query against the local resolver. If dig @1.1.1.1 works and
dig alone does not, the fault is your resolver, not the record.
getent hosts HOST # resolution as the C library sees it
getent honours /etc/hosts and nsswitch.conf; dig does not. When an
application and dig disagree, this is usually why.
Routing
ip route # routing table
ip route get 8.8.8.8 # which route and source IP will be used
ip neigh # ARP cache
ip rule list # policy routing rules
ip route get answers the only routing question that matters during an
incident: which interface and source address this specific destination will use.
HTTP and TLS
curl -v https://HOST
curl -sS -o /dev/null -w 'dns=%{time_namelookup} tcp=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' https://HOST
curl --resolve HOST:443:1.2.3.4 https://HOST # bypass DNS, test one backend
That -w timing breakdown is the fastest way to attribute latency. Slow
time_namelookup is DNS; slow time_connect is the network; slow
time_starttransfer is the application.
openssl s_client -connect HOST:443 -servername HOST </dev/null
echo | openssl s_client -connect HOST:443 2>/dev/null | openssl x509 -noout -dates -subject
Always pass -servername — without SNI you may be shown a completely different
certificate than a browser sees.
Firewalls
sudo iptables -L -n -v --line-numbers
sudo nft list ruleset
sudo ufw status verbose
# Are packets being dropped by conntrack?
sudo conntrack -S
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
Conntrack exhaustion presents as random, intermittent connection failures under
load while everything looks healthy. Compare count against max.
Packet capture
sudo tcpdump -i any -n port 443
sudo tcpdump -i any -n host 10.0.0.5 and port 5432
sudo tcpdump -i any -n -c 100 -w capture.pcap # write for Wireshark
sudo tcpdump -i any -n 'tcp[tcpflags] & (tcp-rst) != 0' # RSTs only
-n disables name resolution — without it tcpdump generates its own DNS traffic
and pollutes the capture. Filtering for RSTs is the quickest way to find who is
actively refusing connections.
Throughput and saturation
sar -n DEV 1 5 # per-interface throughput
sar -n EDEV 1 5 # per-interface errors
iftop -i IFACE # live per-connection bandwidth
nload IFACE
iperf3 -s # on the server
iperf3 -c SERVER -t 30 # on the client
Fast checks
ip -br addr # interfaces at a glance
ss -s # socket summary by state
ss -tan state syn-sent # stuck outbound handshakes
sudo tcpdump -i any -n -c 20 icmp # is anything ICMP arriving
curl -sS -o /dev/null -w '%{http_code}\n' https://HOST