# Troubleshooting Networks

> A calm, methodical way to debug 'the internet is broken' - work up the layers (link, IP, gateway, DNS, destination), then use ping, traceroute, dig, and a packet capture to read exactly where the conversation died.


---

# Troubleshooting Networks

Something doesn't load. A page hangs on "Connecting…", an API call times out, the whole office Slack goes quiet at once. The instinct is to start poking - toggle Wi-Fi, reload, blame the router, restart the laptop, maybe the server. That's guessing, and it's slow and stressful because you never know if the thing you just changed was the thing that mattered.

There's a calmer way - the way people who fix networks for a living actually work. A network connection is a stack of layers, each depending on the one below it. When something breaks, you walk *up* the stack, asking one yes/no question at each rung: is the link up? do I have an address? can I reach the gateway? can I turn a name into an address? can I reach the far end? The first "no" is your answer - everything above it is irrelevant, everything below it is fine. This guide teaches you that method, then hands you the small set of tools that answer each question.

## How to read this

- **In a panic right now?** Jump to the symptom cheat-card at the top of [Phase 1: Work Up the Layers](01-work-up-the-layers.md) - it points "can't load anything" / "one site only" / "slow" straight at the rung to check.
- **Want it to finally make sense?** Read in order. Phase 1 gives you the method, Phase 2 gives you the everyday tools, and Phase 3 shows you how to read the wire itself when the easy tools run out.

## The phases

1. **[Work Up the Layers](01-work-up-the-layers.md)** - the method: a short list of yes/no checks, from "is the cable plugged in" to "can I reach the destination," mapped onto the TCP/IP layers. Stop guessing; isolate.
2. **[The Core Tools](02-the-core-tools.md)** - annotated transcripts of `ping`, `traceroute`/`tracert`, and `dig`/`nslookup`. For each: what its output *actually tells you*, so you can read the answer instead of memorizing flags.
3. **[Reading a Packet Capture](03-reading-a-packet-capture.md)** - what a capture *is*, what you can *see* in it (the handshake, retransmissions, resets, which side went quiet), and how to read it to answer "where exactly did the conversation break." Concept-first, not a button tour.

> This guide is about *diagnosis* - finding where it breaks. Configuring networks (subnets, routing tables, firewall rules) and the deeper protocol mechanics are their own topics; where you need that grounding, we link to [The TCP/IP Model](/guides/tcp-ip-model) and [IP, DNS, and Ports](/guides/ip-dns-and-ports).

---

Related guides: [IP, DNS, and Ports](/guides/ip-dns-and-ports) · [The TCP/IP Model](/guides/tcp-ip-model) · [How the Internet Works](/guides/how-the-internet-works)


---

# Work Up the Layers

When the network is down, the room fills with theories - "it's the DNS," "it's the firewall," "it's their server" - and every guess costs a restart, a config change, a few more minutes of the page still not loading. A network connection isn't one thing; it's a stack of things, each depending on the one beneath it. A guess picks a rung at random.

The fix: **don't guess which rung broke - test them one at a time, bottom up, and stop at the first failure.** Each rung is a single yes/no question. Hit a "no," and you're done diagnosing: everything *below* is proven healthy, everything *above* is irrelevant until this one's fixed. [Phase 2](02-the-core-tools.md) covers the tools that answer these questions.

## The symptom cheat-card

> **Read your symptom, jump to the rung it points at, breathe. You're not guessing anymore.**

| The symptom | What it usually means | Start at |
|---|---|---|
| **Nothing loads** - every site, every app, all at once | Something low broke: no link, no IP, or no gateway | Rung 1 → 2 → 3 (§ below) |
| **One site/service is down**, everything else is fine | The low layers are healthy; it's name resolution or that one destination | Rung 4 (DNS), then Rung 5 |
| **Names fail but raw IPs work** (a URL hangs, but pinging an IP succeeds) | Classic DNS failure - the lookup, not the network | Rung 4 (DNS) |
| **Everything is slow / times out intermittently**, but does eventually work | The path exists but a hop is congested or lossy | Rung 5 (latency + path) - `ping`/`traceroute` |
| **"It's down" but you can't even tell where** | You don't have a fact yet | Rung 1 and walk up - collect facts, not theories |

Now the rungs themselves, bottom to top.

## The layers you're walking up

Each rung maps onto a layer of the TCP/IP model - a network built in stacked levels, each relying on the level below. (If that model is new, [The TCP/IP Model](/guides/tcp-ip-model) is the grounding; you can also just follow the picture below.)

```mermaid
flowchart TD
  r1["Rung 1 - Is the LINK up? (cable / Wi-Fi connected) - Link"]
  r2["Rung 2 - Do I have an IP ADDRESS? (am I a citizen of a net?) - Internet (addressing)"]
  r3["Rung 3 - Can I reach the GATEWAY? (the router off my network) - Internet (routing)"]
  r4["Rung 4 - Can I RESOLVE A NAME? (DNS: turn name → IP) - Application"]
  r5["Rung 5 - Can I reach the DESTINATION? (the far server / API) - Transport/App"]
  r1 -->|yes, walk up| r2 -->|yes| r3 -->|yes| r4 -->|yes| r5
```

📝 **Terminology.** Your *gateway* (or *default gateway*) is the router that connects your local network to everything else. If you can't reach the gateway, you can't reach the internet at all, no matter how healthy your laptop is.

### Rung 1 - Is the link up?

Is there a physical (or Wi-Fi) connection at all? An unplugged cable, a dropped Wi-Fi association, a disabled interface - the network equivalent of "is it plugged in." It's first because nothing above it can work without it, and it's the rung people skip because it feels too dumb to check. Check it anyway.

```console
$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 ...
2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
```
*What just happened:* `ip link show` lists your network interfaces and their state. `wlan0` is the Wi-Fi adapter; the flags in angle brackets tell the story. `UP` means the interface is administratively enabled; **`LOWER_UP` means the physical/radio link is actually live** - a cable is seated, or Wi-Fi is associated. Missing `LOWER_UP` (or `state DOWN`) means stop here: the cable's out or Wi-Fi dropped. (Windows: `ipconfig`; macOS: `ifconfig` or the Wi-Fi menu.)

⚠️ **Gotcha.** `lo` (loopback) is *always* `UP` - it's the interface your machine uses to talk to itself (`127.0.0.1`). Seeing `lo: UP` tells you nothing about your real connection. Look at the named adapter (`wlan0`, `eth0`, `en0`), never loopback.

### Rung 2 - Do I have an IP address?

Did I get an address on this network? The link can be up, but if your machine never got an IP (usually via DHCP), it isn't a participant - it can send and receive nothing useful.

```console
$ ip addr show wlan0
2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    inet 192.168.1.74/24 brd 192.168.1.255 scope global dynamic wlan0
```
*What just happened:* `inet 192.168.1.74/24` is a real, DHCP-assigned address (`scope global dynamic`). You have an IP; move up.

⚠️ **Gotcha.** An address starting with **`169.254.x.x`** (or `fe80::` for IPv6 link-local) is *self-assigned* - your machine asked DHCP for a real one, got no answer, and made one up. That's not "you have an IP," it's "you failed to get one." Treat `169.254.*` as a Rung-2 failure: the DHCP server (often the router) didn't respond. (📝 *DHCP* = the service that automatically leases IP addresses to devices that join the network.)

### Rung 3 - Can I reach the gateway?

Can I talk to the router that's my door to the outside world? You have an address; now prove you can reach the one machine everything off-network depends on. Find the gateway, then ping it.

```console
$ ip route show
default via 192.168.1.1 dev wlan0 ...
$ ping -c 3 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=2.31 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=1.98 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=2.10 ms

--- 192.168.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
```
*What just happened:* `ip route show` gave the `default` route - the gateway, `192.168.1.1`. `ping` sent three probes and got three replies, `0% packet loss` - your conversation with the router works; any problem is *above* this rung. (Ping details in [Phase 2](02-the-core-tools.md); for now, replies = reachable.) Timeouts here would mean the break is local - your router or the link to it - not some distant server.

### Rung 4 - Can I resolve a name? (DNS)

Can I turn a human name like `example.com` into an IP address? Almost everything you type is a name, and names mean nothing until DNS translates them. This rung is special because it's the single most common cause of "the internet is broken" that *isn't* the network - the path is fine, the lookup is what failed.

The clean test is to compare a *name* against a raw *IP*:

```console
$ ping -c 2 example.com
ping: example.com: Name or service not known
$ ping -c 2 93.184.216.34
64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=11.4 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=56 time=11.2 ms
```
*What just happened:* pinging the *name* failed with `Name or service not known` - the resolver couldn't find an address. Pinging a raw IP directly *worked*. That split is the signature of a DNS problem: the network carries packets fine (the IP ping proves it), it's the **name-to-address lookup** that's broken. Raw IPs work, names don't → go straight to `dig`/`nslookup` in [Phase 2](02-the-core-tools.md). (See [IP, DNS, and Ports](/guides/ip-dns-and-ports) for how names, addresses, and ports fit together.)

💡 **Key point.** "Is it DNS?" is the most useful single question in network troubleshooting, and the IP-vs-name comparison answers it in two commands. The community joke "It's always DNS" exists because this rung fails *constantly* and looks like a total outage when it isn't.

### Rung 5 - Can I reach the destination?

With a name resolved to an IP, can I actually reach *that specific server* - and how well? This is the top of the stack: link, address, gateway, and DNS are all proven, so anything wrong now is out in the path or at the far end. Two things matter here: does it reply at all (reachability), and how slowly/reliably (latency and loss).

```console
$ ping -c 4 93.184.216.34
64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=11.4 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=56 time=11.2 ms
64 bytes from 93.184.216.34: icmp_seq=3 ttl=56 time=243 ms
64 bytes from 93.184.216.34: icmp_seq=4 ttl=56 time=11.6 ms

--- 93.184.216.34 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 11.2/69.3/243/100.1 ms
```
*What just happened:* all four probes came back (`0% packet loss`) - reachable - but probe 3 spiked to `243 ms` against a ~11 ms baseline. One slow spike is normal jitter; if *most* probes were that high, or some never returned, that's a path problem (a congested or failing hop) - reach for `traceroute` to find *where*.

🪖 **War story.** "The whole site is down." Walking the rungs: link up, IP fine, gateway pings in 2 ms, raw IP to the server pings fine too - but the site's *name* wouldn't resolve. Rung 4. A DNS record had quietly expired; the servers, network, and path were healthy the entire time. Ten minutes of "restart the load balancers" would have changed nothing.

## Recap

1. A connection is a **stack of layers**; debug by walking *up* it and stopping at the first "no."
2. **Rung 1 - link:** is the interface `LOWER_UP`? (Ignore `lo`.)
3. **Rung 2 - IP:** do you have a real address, not a `169.254.*` self-assigned one?
4. **Rung 3 - gateway:** can you ping the `default` route? If not, the break is local.
5. **Rung 4 - DNS:** name fails but raw IP works = it's DNS, the most common "outage" that isn't one.
6. **Rung 5 - destination:** reachable? how's the latency and loss? This hands you off to `traceroute`.

You now have the method. Next, the three tools that answer rungs 3 through 5 - and what their output is really telling you.


---

# The Core Tools

Phase 1 taught you *which* question to ask at each rung. This phase hands you the three tools that answer the top three rungs, and - more importantly - teaches you to *read* their output. Most people run `ping` and `traceroute`, glance at the wall of numbers, and feel none the wiser. The numbers aren't the point; the *shape* of them is. Once you know what each tool is really telling you, a single run gives you a fact, not a vibe.

Three tools, three jobs:

- **`ping`** - *Can I reach it, and how fast?* (reachability + latency)
- **`traceroute`** / **`tracert`** - *What path do my packets take, and where do they die?*
- **`dig`** / **`nslookup`** - *Is it DNS? What address does this name actually resolve to?*

## `ping` - reachability and latency

`ping` sends a tiny "are you there?" probe to a host and waits for an "I'm here" reply, over and over. It's the simplest possible question - *can these two machines exchange a packet at all?* - and the round trip also measures how long that exchange takes. (📝 *Round-trip time*, or RTT, is the time from sending a probe to getting its reply - there and back, not one way.)

Its output tells you two things, and only two: **whether replies come back** (reachability) and **how long they take and how consistently** (latency and loss).

```console
$ ping -c 5 example.com
PING example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=11.4 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=56 time=11.2 ms
64 bytes from 93.184.216.34: icmp_seq=3 ttl=56 time=11.9 ms
64 bytes from 93.184.216.34: icmp_seq=4 ttl=56 time=11.3 ms
64 bytes from 93.184.216.34: icmp_seq=5 ttl=56 time=11.5 ms

--- example.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 11.2/11.4/11.9/0.24 ms
```
*What just happened:* the first line already did you a favor - it resolved `example.com` to `93.184.216.34`, so a successful ping quietly proves DNS worked too. Five probes replied, each around `11 ms` and tightly clustered. The summary is the verdict: **`0% packet loss`** (solidly reachable) and a low `mdev` (jitter) of `0.24 ms` - rock-steady timing.

Now a sick connection - same command, very different shape:

```console
$ ping -c 5 example.com
64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=11.5 ms
Request timeout for icmp_seq=2
64 bytes from 93.184.216.34: icmp_seq=3 ttl=56 time=410 ms
Request timeout for icmp_seq=4
64 bytes from 93.184.216.34: icmp_seq=5 ttl=56 time=388 ms

--- example.com statistics ---
5 packets transmitted, 3 received, 40% packet loss
rtt min/avg/max/mdev = 11.5/269.8/410/186.4 ms
```
*What just happened:* two probes never came back (`Request timeout`), and the ones that did swung between `11 ms` and `410 ms`. The summary spells out the trouble: **`40% packet loss`** and huge spread (`mdev` of `186 ms`). The host is technically reachable but the path is congested, overloaded, or failing. `ping` has told you *that* it's bad; it can't tell you *where*. That's the next tool's job.

⚠️ **Gotcha.** "No ping reply" does **not** always mean "host is down." Plenty of servers and firewalls are deliberately configured to ignore ping (ICMP) while happily serving real traffic on, say, port 443. Use ping as a *positive* signal (replies = definitely reachable); treat *no* reply as "inconclusive, check another way," not proof of death.

💡 **Key point.** Read ping in order: (1) the resolved IP on line 1 - DNS worked. (2) `% packet loss` - reachable at all, and reliably? (3) `avg` and `mdev` - fast and steady, or slow and jittery? Three glances, full diagnosis.

## `traceroute` / `tracert` - the path, and where it dies

Your packets don't teleport to the destination - they hop from router to router, each handoff a "hop." `traceroute` (`tracert` on Windows) reveals that hidden chain: it lists every router between you and the destination, in order, with the latency to each - a receipt for the journey, one line per stop.

**The clever trick.** Every packet carries a TTL - "time to live" - a counter of how many hops it's allowed before a router discards it and reports back. `traceroute` sends a packet with TTL 1 (dies at hop 1, which announces itself), then TTL 2 (dies at hop 2), and so on, mapping the path one router deeper each round. You don't need to remember the trick - it just explains why the output is a numbered list of routers getting progressively farther away.

Its output tells you the *path* your traffic takes, and - the part you came for - **the hop where it stops getting through**, which is the location of the problem.

```console
$ traceroute example.com
traceroute to example.com (93.184.216.34), 30 hops max, 60 byte packets
 1  192.168.1.1 (192.168.1.1)        1.92 ms   1.88 ms   2.04 ms
 2  10.0.0.1 (10.0.0.1)             12.4 ms   12.1 ms   12.9 ms
 3  72.14.215.85 (72.14.215.85)     14.0 ms   13.8 ms   14.2 ms
 4  108.170.246.1 (108.170.246.1)   22.7 ms   22.3 ms   23.1 ms
 5  93.184.216.34 (93.184.216.34)   24.1 ms   23.9 ms   24.4 ms
```
*What just happened:* five hops, start to finish. **Hop 1 is your own gateway** (`192.168.1.1`, ~2 ms - Rung 3 from Phase 1, confirmed). Hops 2-4 are routers across your ISP and the internet, latency climbing gently (normal - more distance, more time). **Hop 5 is the destination itself** - the trace reached the end, meaning the path is intact end to end. (Each hop is probed three times, hence three numbers per line.)

Now the run that earns the tool its keep - a trace that *dies*:

```console
$ traceroute example.com
traceroute to example.com (93.184.216.34), 30 hops max, 60 byte packets
 1  192.168.1.1 (192.168.1.1)        1.95 ms   1.90 ms   2.01 ms
 2  10.0.0.1 (10.0.0.1)             12.2 ms   12.0 ms   12.6 ms
 3  72.14.215.85 (72.14.215.85)     14.1 ms   13.9 ms   14.3 ms
 4  * * *
 5  * * *
 6  * * *
```
*What just happened:* the trace got cleanly through hops 1-3, then hit `* * *` and never recovered - each `*` is a probe with no reply. Reading: **your packets travel fine to hop 3, and something at or after hop 4 is swallowing them** - out past your gateway and ISP's first hops, at a router you don't control. That's a fact you can act on (wait it out, route around it, report it), not a guess.

⚠️ **Gotcha.** A few `* * *` in the *middle* of an otherwise-complete trace are often harmless - many routers forward your traffic perfectly but don't reply to the traceroute probes themselves (ICMP de-prioritized or blocked). A trace can show `* * *` at hop 7 and still reach the destination fine at hop 12. The failure that *matters* is when the stars start and the trace **never reaches the destination**.

📝 **Terminology.** A *hop* is one router-to-router handoff. "Three hops out" means three routers between you and there.

## `dig` / `nslookup` - is it DNS?

`dig` ("domain information groper") asks a DNS server one direct question - *what address does this name map to?* - and shows the raw answer. It's the tool that turns "I think it's DNS" into "it is/isn't DNS, here's the proof." (`nslookup` does the same job and ships on Windows by default; `dig` gives more detail and is the one most engineers reach for.)

Its output tells you whether a name resolves at all, *what* it resolves to, and which server gave the answer. When Phase 1's IP-vs-name test pointed at Rung 4, this is the tool that confirms it and shows the actual record.

```console
$ dig example.com

; <<>> DiG 9.18.1 <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54321
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;example.com.            IN  A

;; ANSWER SECTION:
example.com.        3600    IN  A   93.184.216.34

;; Query time: 24 msec
;; SERVER: 192.168.1.1#53(192.168.1.1)
```
*What just happened:* the two lines that matter are **status** and **answer**. `status: NOERROR` means the lookup succeeded. The `ANSWER SECTION` is the payoff: `example.com.` resolves to an **`A` record** (an IPv4 address) of `93.184.216.34`, with a `3600`-second TTL (how long this answer may be cached). `SERVER: 192.168.1.1#53` shows which resolver answered - your gateway, on standard DNS port 53. (📝 An *A record* maps a name to an IPv4 address; `AAAA` does the same for IPv6.)

Here's the failure that confirms a DNS problem:

```console
$ dig doesnotexist.example

; <<>> DiG 9.18.1 <<>> doesnotexist.example
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 11111
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;doesnotexist.example.       IN  A
```
*What just happened:* **`status: NXDOMAIN`** - "non-existent domain" - and `ANSWER: 0`. DNS itself worked fine (it answered you promptly); its answer is "that name does not exist." Very different from a network failure: the lookup machinery is healthy, the *name* is the problem (a typo, an expired record, an unregistered domain). If the command had hung and timed out instead, that points at the DNS server being unreachable - a lower rung.

💡 **Key point.** `dig` separates two failures people constantly confuse: **`NXDOMAIN`** = "DNS works, the name is bad," versus **a timeout / no response** = "I can't even reach the DNS server." The first is a name problem; the second is a network problem one rung lower.

🪖 **War story.** A deploy "broke the API" for half the users and not the others. `ping` to the API's IP was flawless everywhere. But `dig api.internal` returned *different* `A` records depending on who ran it - one office's resolver still had the old, retired server cached, TTL not yet expired. The network was perfect; two populations were resolving the same name to two different machines. Without `dig` showing the actual record each side got, it looked like a baffling intermittent outage.

## Recap

1. **`ping`** answers *reachable + how fast*: read the resolved IP (DNS worked), then `% packet loss` (reachable/reliable?), then `avg`/`mdev` (fast/steady?). No reply ≠ definitely down.
2. **`traceroute`/`tracert`** answers *what path + where it dies*: hop 1 is your gateway, the last hop should be the destination. `* * *` that never reaches the end = the break, and tells you *which hop out*.
3. **`dig`/`nslookup`** answers *is it DNS*: `NOERROR` + an `ANSWER` = name resolves; `NXDOMAIN` = DNS fine, name bad; timeout = can't reach the DNS server (lower rung).
4. Together they cover Rungs 3-5: gateway reachability, the path to the destination, and the name lookup in between.

These three tools see *summaries* - replies, hops, records. When even they can't tell you where a conversation broke, you drop down to watching the actual packets on the wire. That's the last tool, and it's next.


---

# Reading a Packet Capture

Sometimes the easy tools run out. `ping` says the host is reachable, `traceroute` says the path is clean, `dig` says the name resolves - and yet the app still hangs, the upload still stalls. Every summary tool is green, but the thing is broken. This is when you stop looking at summaries and look at the *actual conversation* - every packet, in order, on the wire. The tool for that is a **packet capture**, usually read in **Wireshark**.

This phase isn't a tour of Wireshark's buttons - those change. What matters is knowing *what a capture is* and *what to look for*, because once you can read the shape of a conversation, you can point at the exact packet where it went wrong. Not "it's broken somewhere out there," but "here, at this packet, this side stopped talking."

## What a packet capture actually is

A packet capture is a recording of **every packet that crossed a network interface**, in order, timestamped. Where `ping` and `traceroute` send their *own* probes and show summaries, a capture is passive: it watches the real traffic your applications are already sending and writes down everything it sees. The difference between asking "is the road open?" and parking by the road filming every car that drives past.

Because there's no summarizing, no guessing, no "inconclusive" - every packet is *right there*: who sent it, to whom, what kind, when. If a conversation broke, the break is *in the recording*. Your job shrinks from "diagnose an invisible problem" to "read a transcript and find the line where it went silent."

📝 **Terminology.** A *packet* is one chunk of data sent across the network, wrapped in headers saying where it's from, where it's going, what kind it is. A *capture* (or "pcap," after the file format) is an ordered list of them. *Wireshark* is the program that records and displays captures in a readable table.

```text
   What a capture looks like - one row per packet, top to bottom in time:

   No.  Time     Source         Destination    Proto  Info
   ───────────────────────────────────────────────────────────────────────
    1   0.000    192.168.1.74   93.184.216.34  TCP    50312 → 443 [SYN]
    2   0.011    93.184.216.34  192.168.1.74   TCP    443 → 50312 [SYN, ACK]
    3   0.011    192.168.1.74   93.184.216.34  TCP    50312 → 443 [ACK]
    4   0.012    192.168.1.74   93.184.216.34  TLS    Client Hello
    5   0.024    93.184.216.34  192.168.1.74   TLS    Server Hello
   ───────────────────────────────────────────────────────────────────────
        │        └── who sent it   └── who it's for   │      └── what happened
        └── order + timestamp                         └── protocol
```

Read it top to bottom, like a chat log between two machines. **Source** and **Destination** tell you who's talking; **Time** tells you when; **Info** tells you *what kind* of packet it is. Learning to read network trouble is mostly learning to recognize a few patterns in that `Info` column.

## Pattern 1: the handshake - does the conversation even start?

Before two machines exchange real data over TCP, they perform a three-step greeting, the **three-way handshake**: one side says "let's talk" (`SYN`), the other says "sure" (`SYN, ACK`), the first confirms "great, talking now" (`ACK`). Only then does data flow. (📝 *TCP* guarantees ordered, reliable delivery - most things you use ride on it. *SYN* and *ACK* are packet flags: "synchronize" and "acknowledge.")

Look for those exact three packets at the *start* of a conversation, in order:

```text
    1   0.000  192.168.1.74   93.184.216.34  TCP  50312 → 443 [SYN]        ← "let's talk"
    2   0.011  93.184.216.34  192.168.1.74   TCP  443 → 50312 [SYN, ACK]   ← "sure"
    3   0.011  192.168.1.74   93.184.216.34  TCP  50312 → 443 [ACK]        ← "great, go"
```
*What just happened:* your client (`192.168.1.74`) opened a connection to the server on port 443. `SYN` went out, `SYN, ACK` came back ~11 ms later, `ACK` sealed it - a clean, complete handshake. **This is the single most useful thing to check first**: if it completes, the two machines *can* reach each other and the trouble is in what comes after (data, TLS, application). If it doesn't, the problem is at the connection level and you never got to the real conversation.

```text
   The telltale broken-start: SYN with no answer, again and again

    1   0.000  192.168.1.74   203.0.113.9   TCP  50318 → 443 [SYN]
    2   1.001  192.168.1.74   203.0.113.9   TCP  [TCP Retransmission] 50318 → 443 [SYN]
    3   3.005  192.168.1.74   203.0.113.9   TCP  [TCP Retransmission] 50318 → 443 [SYN]
```
*What just happened:* your machine sent a `SYN` and got *nothing* back, so it retried after 1 second, then 3 (TCP backs off and retries). The server never completes the greeting - the far end is down, a firewall is silently dropping the `SYN`, or it's the wrong address/port. This is invisible to `ping` if the host answers pings but blocks port 443 - the capture shows the truth summary tools missed.

## Pattern 2: retransmissions - the conversation is struggling

TCP guarantees delivery, so when a packet goes unacknowledged (lost or too slow), the sender **retransmits** it. A retransmission isn't itself a failure - it's TCP doing its job. But *lots* of them is the fingerprint of a lossy or congested path, the network equivalent of "sorry, you cut out, say that again" happening over and over.

Wireshark flags these in the `Info` column:

```text
   42  2.104  192.168.1.74   93.184.216.34  TCP  [TCP Retransmission] 50312 → 443
   43  2.339  93.184.216.34  192.168.1.74   TCP  [TCP Dup ACK] 443 → 50312
   44  2.610  192.168.1.74   93.184.216.34  TCP  [TCP Retransmission] 50312 → 443
```
*What just happened:* the same data sent more than once (`[TCP Retransmission]`) and the receiver repeatedly saying "I'm still missing that piece" (`[TCP Dup ACK]`). A handful is normal; a capture *littered* with these means packets are being lost in the path - the "40% packet loss" you might have seen in `ping`, now shown packet by packet. The connection still *works*, but it's slow and stuttering because TCP is spending its time re-sending. This is what "the network is slow" looks like up close.

## Pattern 3: the reset - someone hung up hard

A normal connection closes politely with a `FIN` ("I'm done, let's wrap up") from each side. A **`RST` ("reset")** is the opposite: an abrupt "this is over, *now*," no negotiation - a door slammed rather than closed. Something *actively refused* or *killed* the connection.

Look for an `RST` packet, especially right after a request - and *which side sent it*:

```text
   18  0.140  192.168.1.74   203.0.113.9   HTTP  GET /api/orders HTTP/1.1
   19  0.151  203.0.113.9    192.168.1.74  TCP   443 → 50320 [RST, ACK]
```
*What just happened:* the client sent a real request (`GET /api/orders`), and the **server immediately answered with `RST`** instead of data. The far end didn't time out or lose packets - it *deliberately* tore the connection down. Common causes: nothing is listening on that port, a firewall is configured to reject (not silently drop), or the server's application crashed/refused the request. The crucial detail is **direction**: the `RST` came *from* `203.0.113.9` (the server), so the rejection is at the far end, not yours.

⚠️ **Gotcha.** Direction is everything in a capture, and it's what people misread. "Packets aren't getting through" is meaningless until you know *which side stopped sending or started rejecting*. Find the last packet *your* side sent and the last packet *their* side sent - whoever went quiet (or sent the `RST`) first is where to look. A capture's whole value is making "whose fault" a fact you can read, not an argument.

## How to read any capture: find where it went quiet

You don't need to understand every packet. The method is Phase 1's "first failure wins," applied to a transcript:

```mermaid
flowchart TD
  q1{1. Did the handshake complete?}
  q1 -->|no| a1[connection can't start:<br/>down / firewall / wrong port]
  q1 -->|yes| q2{2. Did real data flow both ways?}
  q2 -->|no| a2[one side never replied -<br/>see who went silent]
  q2 -->|yes| q3{3. Lots of retransmissions?}
  q3 -->|yes| a3[lossy / congested path<br/>the slow fingerprint]
  q3 -->|no| q4{4. Any RST?}
  q4 -->|yes| a4[someone refused/killed it -<br/>read the DIRECTION]
  q4 -->|no| a5[5. Which side sent the last packet,<br/>and when did it stop? - that's where it broke]
```
*What just happened:* you walked the conversation the same way you walked the layers - top to bottom, stopping at the first thing that's wrong. The capture's gift is that "where did it break" is no longer a theory - it's a specific row, with a sender, a timestamp, and a packet type.

🪖 **War story.** An upload "failed randomly" for one customer and no one else. Every summary tool was clean - ping fine, traceroute fine, DNS fine. The capture told the whole story in three rows: handshake completed, the client sent its data, and then the *server* sent a `RST` the instant the upload crossed a certain size. Not a network problem at all - a request-size limit on the server, rejecting big uploads with a hard reset. No amount of `ping` would ever have shown it.

## Recap

1. A **packet capture** is every packet on the wire, in time order - a transcript of the real conversation, not a summary. The break, if there is one, is *in the recording*.
2. **The handshake** (`SYN` → `SYN, ACK` → `ACK`) tells you if the connection can even start. No completion = trouble at the connection level; complete = trouble is in what follows.
3. **Retransmissions** (and `Dup ACK`s) are TCP resending lost packets - a few are normal, a flood is a lossy/congested path. This is "slow" up close.
4. **An `RST`** is an abrupt refusal - read *which side sent it* to know who killed the connection.
5. To read any capture, walk it like the layers: handshake? data both ways? retransmissions? reset? **who went quiet first?** - stop at the first wrong thing.

That's the full kit: the calm method (walk up the layers), the everyday tools that answer each rung (`ping`, `traceroute`, `dig`), and the deep tool for when the summaries lie (the packet capture). The next time something "just doesn't work," you won't be guessing - you'll be reading.

Related guides: [IP, DNS, and Ports](/guides/ip-dns-and-ports) · [The TCP/IP Model](/guides/tcp-ip-model) · [How the Internet Works](/guides/how-the-internet-works)
