When the network stops answering, the question is not "which command should I use?" but "at which layer is the problem?". This guide gives you a structured network diagnosis method: you start from the symptom, follow a logical path, and identify the root cause. The commands are organised by incident scenario, not alphabetically. This page applies to networking the general diagnosis method of the Troubleshoot module: observe before acting, and change one thing at a time.
What you will learn
- Diagnose a network problem methodically by following the OSI layers
- Choose the right command for the symptom observed
- Interpret the results to identify the root cause
- Use the modern tools (
ip,ss,mtr) rather than the deprecated commands
Prerequisites
Diagnosing means comparing what you observe with what should happen. Without a mental model of how a packet travels, the commands of this guide are only a list to copy. Make sure you master these foundations:
- OSI model: understand the 7 layers and their role
- IP addressing: CIDR notation, masks, subnets
- Protocols: TCP vs UDP, ICMP, DNS
- Routing: default gateway, routing tables
If one of these notions is missing, the Networking course (in French) covers them from the start: OSI model, protocols and addressing, before moving on to troubleshooting in production.
I am in an incident: which path should I follow?
During an outage, the most expensive reflex is to run commands at random. This table points you in the right direction: identify your symptom, run the first command to qualify the problem, then follow the matching path, detailed below.
| Symptom | Path | First command |
|---|---|---|
| Remote machine unreachable | Host unreachable | ping -c 3 <ip> |
| Service/port does not answer | Port does not answer | nc -zv <ip> <port> |
| Name resolution fails | DNS does not work | dig <domain> |
| Slow or unstable connection | Network is slow | mtr <destination> |
| HTTP request in error | HTTP does not work | curl -I <url> |
Remote host unreachable
Symptom: impossible to reach a remote machine (SSH timeout, ping with no answer, connection refused). If it is specifically your SSH access that is lost, in particular after a change to sshd_config, follow the dedicated path Recover SSH access to a server instead: the diagnosis below covers the general case of an unreachable host.
-
Check basic connectivity
Terminal window ping -c 3 192.168.1.100If it answers → The host is reachable, the problem is elsewhere (port, application firewall).
If it times out → Carry on with the diagnosis (ICMP may be blocked).
-
Check your own IP configuration
Terminal window ip addr show# Look for: inet 192.168.x.x/24 on the active interfaceCheck: does the interface have an IP? Is it in the right subnet?
-
Check the route to the destination
Terminal window ip route get 192.168.1.100# Expected result: via 192.168.1.1 dev eth0If
RTNETLINK answers: Network is unreachable→ No route leads to this destination: check the gateway. -
Check the default gateway
Terminal window ip route show default# Expected result: default via 192.168.1.1 dev eth0If missing → Add it with
ip route add default via <gateway>. -
Test the gateway itself
Terminal window ping -c 3 192.168.1.1If it times out → Problem between you and the router (cable, switch, VLAN).
-
Trace the full path
Terminal window mtr -r -c 10 192.168.1.100Interpret: at which hop does packet loss begin?
Essential IP diagnosis commands
The ip command gathers everything ifconfig, route and arp used to do: interfaces, addresses, routes and ARP neighbours. These five invocations cover the essentials of a network inventory, to know by heart before going further:
# Show every interface and its IPsip addr show
# Show only the UP interfacesip link show up
# Show the full routing tableip route show
# Show the ARP neighbours (MAC resolution)ip neigh show
# Show the interface statisticsip -s link show eth0The port does not answer
Symptom: connection refused or timeout on a specific port (SSH, HTTP, database). The nature of the refusal is already a clue: Connection refused means the machine answers but nothing listens, a timeout points to a firewall silently dropping packets.
-
Test connectivity to the port
Terminal window nc -zv 192.168.1.100 22# Debian, Ubuntu (netcat-openbsd):# Success: Connection to 192.168.1.100 22 port [tcp/ssh] succeeded!# Failure: nc: connect to 192.168.1.100 port 22 (tcp) failed: Connection refused# RHEL, AlmaLinux (nmap-ncat):# Success: Ncat: Connected to 192.168.1.100:22.# Failure: Ncat: Connection refused.Connection refused → The port is not listening on the server side.
Timeout → A firewall blocks the flow.
-
Check that the service listens (on the server)
Terminal window ss -tlnp | grep :22# Expected: LISTEN 0 128 0.0.0.0:22 *:* users:(("sshd",pid=1234,fd=3))If no line → The service is not started.
If 127.0.0.1:22 → The service only listens on localhost.
-
Check the distribution firewall (on the server)
Terminal window # Ubuntu/Debian with UFWsudo ufw status verbose# RHEL/AlmaLinux/Rocky with firewalldsudo firewall-cmd --list-allCheck: is the port or service concerned allowed?
-
Inspect the low-level rules (if no manager is active)
Terminal window sudo nft list ruleset | grep -E "22|ssh"# Or on systems still using iptables:sudo iptables -L -n -v | grep -E "22|ssh"Look for: a DROP or REJECT rule on the port concerned.
-
Test from the server itself
Terminal window nc -zv 127.0.0.1 22If OK locally but not remotely → Firewall or listening configuration.
If the nc test succeeds but the application returns no useful answer (the connection opens then stays silent, or systemctl shows active (running) while nothing works), the problem is no longer networking: the process itself is at fault. Carry on with An active service that does not answer.
Essential ss commands
ss replaces netstat to inspect sockets: listening ports, established connections, associated processes. Its filter language avoids printing everything and then sorting with grep, which matters on a server handling thousands of connections:
# Every listening TCP port with its processss -tlnp
# Every listening UDP portss -ulnp
# Established TCP connectionsss -tn state established
# Filter by portss -tn 'sport == :22'
# Filter by remote addressss -tn 'dst 192.168.1.0/24'
# Detailed connection statisticsss -tiDNS does not work
Symptom: impossible to resolve a domain name (ping google.com fails, but ping 8.8.8.8 works).
-
Test DNS resolution
Terminal window dig google.com +short# Expected: 142.250.xxx.xxxIf empty or SERVFAIL → DNS problem.
-
Check the configured DNS server
Terminal window cat /etc/resolv.conf# nameserver 192.168.1.1# or nameserver 127.0.0.53 (systemd-resolved) -
Test with a public DNS
Terminal window dig @8.8.8.8 google.com +shortIf it works → Your local DNS is failing.
-
Query your DNS server directly
Terminal window dig @192.168.1.1 google.com +shortIf it times out → The DNS server is unreachable or port 53 is filtered.
If SERVFAIL or REFUSED → The server answers but refuses or fails to resolve.
-
Check the local DNS cache
Terminal window # On systems using systemd-resolved (Ubuntu by default)resolvectl statisticsresolvectl flush-caches
Essential dig commands
dig queries DNS servers and prints the raw answer: record type, TTL, server that answered. It is this level of detail that nslookup lacks and that lets you tell a stale cache from a badly configured zone:
# Simple query (A record)dig google.com
# Short answer onlydig google.com +short
# MX records (mail servers)dig google.com MX
# Reverse resolution (IP to name)dig -x 8.8.8.8
# Trace the full DNS delegationdig google.com +trace
# Use a specific DNS serverdig @1.1.1.1 google.com
# Show only the answer sectiondig google.com +noall +answerThe network is slow
Symptom: high latency, dragging connections, intermittent timeouts. It is the most delicate diagnosis, because "slow" can come from latency, packet loss or saturated bandwidth: each cause has its tool.
-
Measure latency and loss
Terminal window mtr -r -c 20 google.comInterpret:
- Loss% > 5% = congestion or link problem
- Avg > 100ms to a local server = abnormal
- High StDev = unstable connection
-
Identify the bottleneck
Look at which hop the latency suddenly rises or the losses begin.
-
Test the bandwidth
Terminal window # On the remote serveriperf3 -s# On your machineiperf3 -c <server> -t 30 -
Watch traffic in real time
Terminal window # Global view per connectionsudo iftop -i eth0# Interface statisticsip -s link show eth0 -
Check the interface errors
Terminal window ip -s link show eth0# Read the line of values under RX: then under TX:;# errors, dropped, missed and carrier must stay at 0A
grep errorson this output is a false friend: it only returns the header lines (RX: bytes packets errors dropped missed mcast), never the values, which sit on the next line.
Essential mtr commands
mtr combines ping and traceroute continuously: it replays the path in a loop and accumulates statistics per hop, which makes intermittent problems visible that a single traceroute misses. The TCP mode is precious when routers filter ICMP:
# Report after 10 probesmtr -r -c 10 google.com
# Continuous mode (interactive)mtr google.com
# Show IPs without resolutionmtr -n google.com
# Use TCP instead of ICMPmtr --tcp -P 443 google.com
# Use UDPmtr --udp google.comHTTP does not work
Symptom: web page unreachable, 502/503/504 error, timeout on an API. curl lets you break down the response time step by step (DNS, TCP connection, TLS negotiation, first byte) and point at the faulty link.
-
Test HTTP connectivity
Terminal window curl -I https://example.com# HTTP/2 200 = OK -
Measure the response times
Terminal window curl -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nFirst byte: %{time_starttransfer}s\nTotal: %{time_total}s\n" -o /dev/null -s https://example.comInterpret:
- DNS > 1s → Resolution problem
- Connect > 1s → Network problem or saturated server
- TLS > 2s → Slow TLS negotiation
- First byte > 5s → Slow backend
-
Test without TLS (if applicable)
Terminal window curl -I http://example.com -
Check the response headers
Terminal window curl -v https://example.com 2>&1 | head -50 -
Bypass DNS
Terminal window # Get the real IP of the serverdig +short example.com# Force curl to use this IP without going through DNScurl --resolve example.com:443:<ip> https://example.comIf it works with the direct IP → The problem comes from DNS resolution, not from the web server.
curl commands for diagnosis
curl is much more than a downloader: its -v, -w and -I options make it a complete HTTP probe, able to measure each step of the request and isolate a certificate, redirect or timeout problem:
# Headers onlycurl -I https://example.com
# Verbose (connection details)curl -v https://example.com
# Ignore certificate errors (testing only)curl -k https://example.com
# Custom timeoutcurl --connect-timeout 5 --max-time 10 https://example.com
# Follow redirectscurl -L https://example.com
# HTTP code only (handy in a script)curl -s -o /dev/null -w "%{http_code}\n" https://example.comToolbox by intent
Once the paths are learned, what stays in memory is the intent ("I want to see my routes", "I want to test a port"), not the exact option. These three tables serve as a cheat sheet: start from what you want to do, the command follows.
"I want to see..."
These commands are read-only: they display the state of the system without changing anything, you can run them safely even in production.
| Intent | Command | Example |
|---|---|---|
| My IP and interfaces | ip addr show | ip a |
| My routing table | ip route show | ip r |
| Listening ports | ss -tlnp | - |
| Established connections | ss -tn state established | - |
| Real-time traffic | sudo iftop -i eth0 | - |
| ARP neighbours | ip neigh show | ip n |
| Firewall rules | sudo nft list ruleset | - |
"I want to test..."
These commands send active traffic to a target: keep them for machines you are responsible for or authorised to test.
| Intent | Command | Example |
|---|---|---|
| Whether a machine answers | ping -c 3 <ip> | ping -c 3 8.8.8.8 |
| Whether a port is open | nc -zv <ip> <port> | nc -zv 192.168.1.1 22 |
| The route to a destination | mtr -r <ip> | mtr -r google.com |
| DNS resolution | dig <domain> | dig google.com +short |
| Bandwidth | iperf3 -c <server> | - |
| An HTTP endpoint | curl -I <url> | curl -I https://api.example.com |
"I want to identify..."
These commands cross-reference information to trace back to the source: which process holds a port, who owns an address. The last row, nmap -sV, sends active traffic to the target: the caveat of the previous table applies, your own machines or a written authorisation only.
| Intent | Command | Example |
|---|---|---|
| Which process uses a port | ss -tlnp | grep :<port> | ss -tlnp | grep :80 |
| The connections of an IP | ss -tn 'dst <ip>' | ss -tn 'dst 10.0.0.1' |
| The owner of an IP | dig -x <ip> | dig -x 8.8.8.8 |
| The name servers of a domain | dig <domain> NS | dig google.com NS |
| The version of a service | nmap -sV -p <port> <ip> | nmap -sV -p 22 192.168.1.1 |
Quick troubleshooting
This table condenses the most frequent network outages with their probable cause and the solution to try first. It does not replace the detailed paths above, but it is often enough to unblock simple cases.
| Symptom | Probable cause | Solution |
|---|---|---|
ping OK to the IP, failure to the name | Failing DNS | Test dig @8.8.8.8, check /etc/resolv.conf |
Connection refused on a port | Service stopped or listening on 127.0.0.1 | ss -tlnp, restart the service, fix the listening address |
| Timeout on a precise port, ping OK | Firewall dropping the packets | ufw status (Ubuntu), firewall-cmd --list-all (RHEL), nft list ruleset |
| No IP on the interface | DHCP failure or interface DOWN | ip link set <iface> up, then Netplan on Ubuntu or NetworkManager on RHEL |
ping: connect: Network is unreachable | No route to the destination, default gateway missing | ip route show default, add the default route |
From <your IP> ... Destination Host Unreachable | A host on the local network, or the gateway, does not answer ARP: switched off, wrong VLAN, wrong address | ip neigh show (FAILED entry), check the targeted machine |
| Intermittent high latency | Congestion or loss on a hop | mtr -r -c 20 <target> to locate the faulty hop |
Common network diagnosis traps
The ping does not answer = machine switched off?
No. ICMP is often filtered. A machine can be perfectly reachable on its service ports while ignoring pings. Always test with nc -zv on a specific port.
The port is open = the service works?
No. A port can be listening (LISTEN) without the service being functional. For example, a web server can listen on port 80 but return 500 errors. Always test the application protocol (curl, mysql -e "SELECT 1").
DNS resolution works = no DNS problem?
No. The DNS cache can hide a problem. Flush the cache (resolvectl flush-caches) and test again. Also check the TTL of the records.
traceroute shows * = router down?
No. The * * * mean the router does not answer ICMP TTL-exceeded packets, not that it is down. Traffic may very well go through. Only a constant packet loss from one hop onwards points to a problem.
ss shows ESTABLISHED = connection alive?
Not always. A connection can stay ESTABLISHED even if the other end is dead (half-open). TCP keepalives detect it, but with a delay. Check the traffic counters (ss -ti).
Security warnings
Network diagnosis tools are double-edged: the same commands that help you locate an outage also serve to map a network, intercept traffic or obtain a privilege escalation. Before installing them everywhere and handing out sudo rights, measure what each one really allows.
Beyond these extreme cases, installing these tools itself increases the attack surface of a server: nmap can trigger security alerts, tcpdump captures sensitive data (passwords, tokens), netcat can serve as a backdoor and iftop needs elevated privileges to capture traffic. Prefer dedicated diagnosis bastions rather than installing these tools on your production servers.
Ready-to-use recipes
When the incident repeats, you might as well script the diagnosis: these three scripts chain the checks of the previous paths and produce a complete inventory in one command, handy to archive in a post-mortem.
Full diagnosis of a host
This script combines ping, route, a test of the standard ports and traceroute: it is the "host unreachable" path, automated.
#!/bin/bash# diagnostic-host.sh <ip>HOST="$1"
echo "=== Diagnosis of $HOST ==="echo -e "\n--- Ping ---"ping -c 3 "$HOST"
echo -e "\n--- Route ---"ip route get "$HOST"
echo -e "\n--- Standard ports ---"for port in 22 80 443; do nc -zv -w 2 "$HOST" "$port" 2>&1done
echo -e "\n--- Traceroute ---"mtr -r -c 5 "$HOST"Full DNS diagnosis
This script queries the A, NS and MX records of a domain, then compares the answer of two public DNS servers: a divergence signals a propagation problem or a failing local resolver.
#!/bin/bash# diagnostic-dns.sh <domain>DOMAIN="$1"
echo "=== DNS diagnosis of $DOMAIN ==="
echo -e "\n--- A resolution ---"dig "$DOMAIN" A +short
echo -e "\n--- Name servers ---"dig "$DOMAIN" NS +short
echo -e "\n--- Mail servers ---"dig "$DOMAIN" MX +short
echo -e "\n--- Test with public DNS ---"echo "Google (8.8.8.8):"dig @8.8.8.8 "$DOMAIN" +shortecho "Cloudflare (1.1.1.1):"dig @1.1.1.1 "$DOMAIN" +shortFull HTTP diagnosis
This script measures the detailed timing of a request (DNS, connection, TLS, first byte) then shows the response headers: enough to locate the slowness before blaming the backend.
#!/bin/bash# diagnostic-http.sh <url>URL="$1"
echo "=== HTTP diagnosis of $URL ==="
echo -e "\n--- Timing ---"curl -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nFirst byte: %{time_starttransfer}s\nTotal: %{time_total}s\nHTTP code: %{http_code}\n" -o /dev/null -s "$URL"
echo -e "\n--- Headers ---"curl -I -s "$URL" | head -20Put it into practice
A diagnosis method is only acquired in front of a real outage. The lab puts you in front of a machine whose network connection is down: it is up to you to walk up the layers with ip, ss and ping, locate the root cause and restore the traffic.
Key points
- Diagnose by OSI layer: physical → data link → network → transport → application
- Use the modern commands:
ipreplacesifconfig/route,ssreplacesnetstat - A ping timeout proves nothing: ICMP is often filtered, test the real port
- An open port ≠ a working service: always test the application protocol
- mtr > traceroute: continuous view, statistics, detection of intermittent problems
- dig > nslookup: parsable output, advanced options, full trace
- Security: tcpdump and nmap widen the attack surface of a production server, prefer dedicated bastions; nmap outside your own networks requires a written authorisation
- Document the results: keep a record of the commands and outputs for post-mortems
Knowledge check
Check that the essentials of this guide stuck. The questions cover only what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: scp: copy files and directories over SSH
A new full quiz with random questions
Work again only on the questions you missed