Build the mental model
Most network debugging goes wrong at the very first step, when someone forms a theory and then tests only that theory. The layered model gives you something better: an order. Every layer depends on the one below it, so a failure low down makes every test above it meaningless. Check link, then IP address, then routing, then DNS, then transport, then application, and stop at the first failure, because everything above it is noise until that is fixed.
The discipline matters because the classic tools prove far less than their reputation suggests. Ping proves that an IP packet reached the host and an ICMP echo reply came back. It proves layer 3 reachability and nothing else. A server whose web process has crashed pings perfectly. A server whose firewall drops ICMP fails to ping while serving traffic happily. Ping is a statement about the network path, never about a service.
Traceroute is subtler still. It does not discover a path; it sends packets with deliberately small TTLs and collects the ICMP time-exceeded replies from whichever routers decremented the TTL to zero. Those replies come from the router's own chosen source address, take their own return path, and are generated by a slow control-plane process that is usually rate-limited. So a hop showing high latency or asterisks is frequently a router deprioritising ICMP rather than real congestion. And with load balancing across equal-cost paths, consecutive probes may traverse entirely different routes, so the path you printed may never have existed as a single path at all.
DNS is the same trap: a successful lookup proves the name resolved. It says nothing about whether the address it returned is reachable, or whether anything is listening there. Each tool answers exactly one question. Know which one.
BOTTOM-UP TROUBLESHOOTING DECISION TREE
---------------------------------------
[ "the site is down" ]
|
v
+-------------------------+
| 1. link up, have an IP? |--- no --> cable, Wi-Fi, DHCP
+-------------------------+
| yes
v
+-------------------------+
| 2. gateway reachable? |--- no --> wrong mask/gw, ARP
+-------------------------+
| yes
v
+-------------------------+
| 3. off-net IP pingable? |--- no --> routing, upstream
+-------------------------+
| yes
v
+-------------------------+
| 4. name resolves? |--- no --> DNS only, NOT the host
+-------------------------+
| yes
v
+-------------------------+ refused -> nothing is listening
| 5. port connects? | timeout -> a firewall is dropping
+-------------------------+
| yes
v
+-------------------------+
| 6. app answers cleanly? |--- no --> logs, TLS, vhost config
+-------------------------+
| yes
v
not this path -- look at the client
WHAT EACH TOOL ACTUALLY PROVES
ping an IP packet made the round trip. NOT that a
service is up, and NOT that a port is open.
trace a list of ICMP TTL-expiry replies. NOT the path,
and its timings are control-plane, not forwarding.
DNS the name resolved. NOT that the answer is reachable.Connect it to a real scenario
Take the most common report you will ever get: the site is down. Resist opening the application logs first.
Start at the bottom with two questions that cost seconds. Does the machine have a real IP and a gateway? Can it reach that gateway? If not, stop: you have a link or DHCP problem and the application is irrelevant.
Next, separate name resolution from reachability, because they fail identically in a browser. Resolve the name, note the address, then try the address directly. If the name fails but the address works, it is DNS. If both fail, it is routing or filtering. That one split eliminates half the possible causes.
Then move to transport. Connecting to the specific port distinguishes the host is up from the service is up, the distinction ping cannot make. A refused connection means something answered and said no, so the host is alive and the process is not listening. A timeout means nothing answered at all, which points at a firewall silently dropping rather than rejecting. That difference is one of the most informative free signals in networking.
Only when the port opens should you read application logs or check TLS. The decision tree below encodes exactly this order, and its second case is the classic one: pings fine, resolves fine, still completely broken.
Try the working example
# A layer-by-layer triage tree. Each check is a fact you have already
# established, NOT a guess. The point is to stop at the FIRST layer that
# fails, because everything above it is meaningless until that is fixed.
CHECKS = [
("link_up", "L1/L2 link", "Interface is down. Check cable, Wi-Fi association, driver."),
("has_ip", "L3 address", "No usable IP. Check DHCP, or a 169.254.x.x self-assignment."),
("gateway_reachable", "L3 local", "Cannot reach the gateway. Wrong mask/gateway, or ARP failing."),
("internet_ip_reachable", "L3 routing", "Off-net IPs unreachable. Routing or the upstream is broken."),
("dns_resolves", "DNS", "Names do not resolve. Wrong resolver, or the zone is broken."),
("port_open", "L4 transport", "Port refuses. The service is down, or a firewall filtered it."),
("app_responds", "L7 application", "TCP connects, app errors. Check logs, TLS, and vhost config."),
]
def triage(name, symptoms):
print("case: " + name)
for key, layer, advice in CHECKS:
ok = symptoms[key]
mark = "PASS" if ok else "FAIL"
print(" [" + mark + "] " + layer)
if not ok:
print(" -> stop here: " + advice)
return layer
print(" -> every layer passes; the fault is not on this path.")
return None
# Symptom sets are hardcoded so this stays deterministic. In real life
# each field is the result of one command you actually ran.
CASES = [
("web page will not load", {
"link_up": True, "has_ip": True, "gateway_reachable": True,
"internet_ip_reachable": True, "dns_resolves": False,
"port_open": False, "app_responds": False,
}),
("ping works, site still down", {
"link_up": True, "has_ip": True, "gateway_reachable": True,
"internet_ip_reachable": True, "dns_resolves": True,
"port_open": False, "app_responds": False,
}),
("laptop has no network at all", {
"link_up": True, "has_ip": False, "gateway_reachable": False,
"internet_ip_reachable": False, "dns_resolves": False,
"port_open": False, "app_responds": False,
}),
("everything connects, 502 in browser", {
"link_up": True, "has_ip": True, "gateway_reachable": True,
"internet_ip_reachable": True, "dns_resolves": True,
"port_open": True, "app_responds": False,
}),
]
for name, symptoms in CASES:
triage(name, symptoms)
print("")
# The classic trap, stated plainly.
print("note: ping succeeding proves L3 only.")
print("case 2 above pings fine and is still completely broken.")case: web page will not load
[PASS] L1/L2 link
[PASS] L3 address
[PASS] L3 local
[PASS] L3 routing
[FAIL] DNS
-> stop here: Names do not resolve. Wrong resolver, or the zone is broken.
case: ping works, site still down
[PASS] L1/L2 link
[PASS] L3 address
[PASS] L3 local
[PASS] L3 routing
[PASS] DNS
[FAIL] L4 transport
-> stop here: Port refuses. The service is down, or a firewall filtered it.
case: laptop has no network at all
[PASS] L1/L2 link
[FAIL] L3 address
-> stop here: No usable IP. Check DHCP, or a 169.254.x.x self-assignment.
case: everything connects, 502 in browser
[PASS] L1/L2 link
[PASS] L3 address
[PASS] L3 local
[PASS] L3 routing
[PASS] DNS
[PASS] L4 transport
[FAIL] L7 application
-> stop here: TCP connects, app errors. Check logs, TLS, and vhost config.
note: ping succeeding proves L3 only.
case 2 above pings fine and is still completely broken.5-minute try-it
Add a new case to CASES for a machine where only DNS is broken, and decide which fields must be True. Then reorder CHECKS so DNS is tested first, re-run it, and explain how the diagnoses go wrong once you abandon the bottom-up order.
One important caution
Treating a successful ping as proof the web service is up: a crashed process still replies to ICMP, and a host that drops ICMP still serves traffic normally.
Reading traceroute hops as the real path: they are ICMP TTL-expiry replies from rate-limited control planes, and ECMP can send consecutive probes down different routes.
RFC 792 - Internet Control Message Protocol — Computer Networking