Lesson 14 — Troubleshooting Tools
dig asks a DNS runner a question and prints the full answer.
Track: DevOps Networking — 1 Month Deep Dive Part: 1 — Networking Foundations Status: Understood and closed Concepts covered: 5 tools — dig, curl, ss, ping, traceroute — each making an earlier lesson visible Builds on: every foundations lesson; this one proves them on a real machine
Every command output below is real, captured on the author’s machine (macOS, Australia, September 2026). Addresses and timings are genuine — which is the point: the theory shows up in real data, not invented examples.
Table of contents
- dig — watching DNS resolve
- Watching the TTL count down
- curl -v — the whole back half of Part 1 on one screen
- ss — every waiter on your machine
- ping — reachability and distance
- traceroute — the ladder of routers, named
- Easy to get wrong
- Old way vs improved understanding
- Terms locked in
- Deliberately not covered yet
- Sources
dig — watching DNS resolve
dig asks a DNS runner a question and prints the full answer. It is Lesson 04 made visible.
$ dig github.com
;; QUESTION SECTION:;github.com. IN A
;; ANSWER SECTION:github.com. 60 IN A 4.237.22.38
;; Query time: 15 msec;; SERVER: 8.8.8.8#53(8.8.8.8)The answer line is the entire DNS lesson in one row:
github.com. 60 IN A 4.237.22.38 │ │ │ │ │ │ │ └── the IPv4 address for the name │ │ └── record type: "A" = "the IPv4 address" │ └── the TTL — how many seconds this may be cached (Lesson 04) └── the name asked about60is the TTL — the “you may remember this for N seconds” from Lesson 04, literal. GitHub set a short 60-second TTL.Ais the record type — one of the “record types” deferred in Lesson 04. “A” means “give me the IPv4 address.”SERVER: 8.8.8.8#53confirms two things from theory: the runner is Google’s8.8.8.8(Lesson 04), reached on port 53 (Lesson 02’s well-known DNS port).Query time: 15 msec— fast, because the answer came from8.8.8.8’s cache, not a fresh walk of root →.com→ GitHub.
Hidden in the full output is also this line:
;; OPT PSEUDOSECTION:; EDNS: version: 0, flags:; udp: 512The word udp — the DNS question rode UDP (Lesson 10’s “just throw it”). Tiny question, tiny answer, ask-again-if-lost. The theory said DNS uses UDP; the machine proved it.
Watching the TTL count down
Running dig repeatedly within one TTL window shows the cache aging in real time.
22:16:25 github.com. 60 IN A 4.237.22.38 ← fresh fetch, full 6022:17:02 github.com. 44 IN A 4.237.22.38 ← 37s later, 44 leftThe TTL dropped from 60 to 44. 8.8.8.8 is saying “I fetched this 16 seconds ago, so you may keep it for 44 more.” Every second, that number falls by one — a live countdown to expiry. Let it reach 0 and the next query jumps back to 60: expired, refetched, reset.
This is Lesson 04’s “nothing stale survives forever,” visible as a ticking number. Query time stays tiny (7–15 ms) throughout because every hit is served from Google’s cache; a name nobody has looked up recently would show 100 ms+, revealing a real chain-walk.
curl -v — the whole back half of Part 1 on one screen
curl -v makes a full web request and prints every layer as it happens: DNS, TCP, TLS, HTTP. Lessons 10, 11, and 12 in sequence.
$ curl -v https://github.com
* Host github.com:443 was resolved.* IPv4: 4.237.22.38* Trying 4.237.22.38:443...* Connected to github.com (4.237.22.38) port 443
* TLS handshake, Client hello (1):* TLS handshake, Server hello (2):* TLS handshake, Certificate (11):* TLS handshake, CERT verify (15):* TLS handshake, Finished (20):* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* Server certificate:* subject: CN=github.com* subjectAltName: host "github.com" matched cert's "github.com"* issuer: C=GB; O=Sectigo Limited; CN=Sectigo Public Server Authentication CA DV E36* expire date: Nov 29 23:59:59 2026 GMT* SSL certificate verify ok.
* using HTTP/2> GET / HTTP/2> Host: github.com> User-Agent: curl/8.7.1> Accept: */*
< HTTP/2 200< date: Mon, 07 Sep 2026 12:17:39 GMT< content-type: text/html; charset=utf-8Read top to bottom, it is Part 1’s second half in order.
DNS + port (Lessons 04, 02):
* Host github.com:443 was resolved. ← DNS lookup done first, silently* IPv4: 4.237.22.38 ← the address (matches dig)* Trying 4.237.22.38:443 ← port 443 chosen because "https"TCP connects (Lesson 10):
* Connected to github.com (4.237.22.38) port 443“Connected” means the TCP three-way handshake completed — SYN, SYN-ACK, ACK. curl doesn’t print the three, but “Connected” is their success.
TLS handshake (Lesson 12), line by line, in exact taught order:
Client hello (1) ← Step 1: "hello + my paint blend"Server hello (2) ← Step 2: "here's my blend"Certificate (11) ← Step 2b: "here's my certificate" (the ID document)CERT verify (15) ← Step 2c: "here's proof I own it" (the anti-impostor signature)Finished (20) ← Step 4: "switching to sealed mode"The CERT verify line is the proof-of-ownership step — the one that kills the impostor. The lesson claimed the server signs this handshake’s values freshly; here the machine does it and prints the line.
The seal, confirmed:
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256TLS 1.3 (the current version from Lesson 12) and the specific scramble method agreed. Everything after this is encrypted on the wire.
The certificate, read out — the padlock panel from Lesson 11, in text:
subject: CN=github.com ← who it's FORsubjectAltName ... matched ← the name check PASSED (promise 2)issuer: ... Sectigo ... CA ... ← the Certificate Authority that signed itexpire date: Nov 29 ... 2026 ← certificates expire (the renewal trap)SSL certificate verify ok. ← "Certificate is valid" — the green check, as a lineverify ok is literally the “Certificate is valid” check from the browser padlock panel, spelled out. issuer: Sectigo is the real CA that vouched for github.com. The expire date is the ticking clock behind the “automate renewal or the whole site breaks” warning.
HTTP (Lesson 11) — the Network-tab capture again:
> GET / HTTP/2> Host: github.com ← the load-bearing header< HTTP/2 200 ← status code: all fine< content-type: text/htmlThe whole chain, in one command:
DNS lookup → TCP connect → TLS handshake → HTTP GET → 200 OKLesson 04 → Lesson 10 → Lesson 12 → Lesson 11ss — every waiter on your machine
ss (or netstat on macOS) lists every open port and connection. It is Lesson 02’s “waiters” made visible.
$ ss -tlnp 2>/dev/null || netstat -an -p tcp | grep LISTEN
tcp4 127.0.0.1.5432 *.* LISTEN ← PostgreSQL (the project database)tcp6 ::1.5432 *.* LISTEN ← same PostgreSQL, IPv6 localhosttcp4 127.0.0.1.6379 *.* LISTEN ← Redis, standard port 6379tcp4 127.0.0.1.5037 *.* LISTEN ← Android Debug Bridgetcp4 *.8081 *.* LISTEN ← a dev server (high port)tcp4 *.5000 *.* LISTEN ← a dev server (high port)tcp4 *.7000 *.* LISTEN ← a dev server (high port)... many 127.0.0.1.<high-port> lines: apps holding local ports for internal use ...Reading one line (macOS writes the port after a dot, not a colon):
tcp4 127.0.0.1.5432 *.* LISTEN │ │ │ │ │ │ │ └── waiting to be contacted (a "waiter", Lesson 02) │ │ └── the port │ └── the address it listens on └── TCP (Lesson 10)The address column is the real lesson — it says WHO can reach each waiter:
127.0.0.1.5432 → localhost only — ONLY this machine can reach it*.5000 → * = ALL addresses — reachable from the network127.0.0.1 (localhost, Lesson 13) means the waiter refuses everyone except this machine. * means it listens on every address the machine has — exposed. PostgreSQL on 5432 listening on 127.0.0.1 is the correct, safe default — a database should not be exposed (Lesson 09), and it is doing the right thing without configuration.
Every port here is above 1023. Not one low port — Lesson 13 confirmed by absence: none of these programs runs as admin, so none could claim a low port even if it tried.
ping — reachability and distance
ping asks one tiny question — “are you there?” — and times the answer.
$ ping -c 4 github.com
PING github.com (20.207.73.82): 56 data bytes64 bytes from 20.207.73.82: icmp_seq=0 ttl=105 time=425.463 ms64 bytes from 20.207.73.82: icmp_seq=1 ttl=105 time=423.653 ms64 bytes from 20.207.73.82: icmp_seq=2 ttl=105 time=426.410 ms64 bytes from 20.207.73.82: icmp_seq=3 ttl=105 time=424.173 ms
4 packets transmitted, 4 packets received, 0.0% packet lossround-trip min/avg/max/stddev = 423.653/424.925/426.410/1.081 msFirst, a mystery that proves a lesson. dig and curl said github.com was 4.237.22.38. ping says 20.207.73.82 — different number, same name. From Lesson 04: GitHub has many addresses and DNS hands out different ones. Same name, multiple machines, live.
Reading a line:
icmp_seq=0,1,2,3— four probes, numbered so replies can be told apart (same idea as TCP sequence numbers, Lesson 10).time=425 ms— the round trip. Slow, and it means something.0.0% packet loss— all four arrived; nothing dropped (Lesson 10 said routers may drop; here none did).
The 425 ms is geography. dig was 7 ms and curl connected fast because they used 4.237.22.38 — a GitHub address near Australia. This ping’s 20.207.73.82 is physically far, and 425 ms is light and cable crossing much of the planet and back. Distance has a floor: the speed of light. This is why companies place servers near users (Lesson 11’s Cloudflare-in-Sydney); 425 ms vs 7 ms is that reason, measured.
A trap in the word ttl=105. This is not the DNS TTL from dig. Same word, unrelated meaning: this is the packet’s hop limit — a counter that drops by one at each router and kills the packet at zero (so lost packets can’t loop forever). Starting near 128 and arriving at 105 means ~23 routers were crossed. Networking reused “TTL” for two different things; knowing that prevents real confusion.
traceroute — the ladder of routers, named
traceroute reveals the actual router hops between you and a destination — Lesson 07’s ladder, made real, one line per hop.
$ traceroute -m 15 github.com
traceroute to github.com (20.207.73.82), 15 hops max 1 * * * 2 172.20.21.254 301.963 ms 3 172.20.22.3 300.830 ms 4 * * * 5 92.62.121.209 301.103 ms 6 unn-149-88-19-189.datapacket.com 301.435 ms 7 vl251.fra-itx7-core-2.cdn77.com 303.542 ms 8 ae41-449.fra10.core-backbone.com 301.714 ms 9 ae2-2025.fra30.core-backbone.com 301.991 ms10 ae64-0.ier02.fra34.ntwk.msn.net 325.033 ms11 po22.rwa04.fra26.ntwk.msn.net 424.520 ms12 be1011.owr02.fra26.ntwk.msn.net 426.274 ms13 be10.ibr01.fra23.ntwk.msn.net 424.396 ms14 be4.owr02.zrh24.ntwk.msn.net 424.897 ms15 be3.owr02.gva20.ntwk.msn.net 425.238 msEach numbered line is one router hop — the real boxes the packet passes through, in order. Lesson 07 said “a message climbs a ladder of routers, each forwarding to the next.” This is that ladder, named.
The * * * lines (hops 1, 4): not errors. Some routers forward the packet but stay silent about themselves (they don’t reply to the probe) — Lesson 13’s deliberate silence. The packet passed through; the router just didn’t announce itself.
The names tell the geography — watch the cities appear:
2-3 172.20.x.x ← PRIVATE addresses (Lesson 09) — inside the ISP's own network5 92.62.121.209 ← the ISP hands off to the public internet6 datapacket.com ← a transit network7 ...fra-itx7...cdn77 ← "fra" = FRANKFURT. Left Australia.8-9 ...fra...core-backbone ← still Frankfurt, a major backbone10-13 ...fra...msn.net ← MICROSOFT's network (msn.net), still Frankfurt14 ...zrh24... ← "zrh" = ZURICH15 ...gva20... ← "gva" = GENEVARead the airport codes: FRA → ZRH → GVA (Frankfurt, Zurich, Geneva). A packet starting in Australia is routed through Europe to reach this GitHub address — which is Microsoft-owned (msn.net), because GitHub belongs to Microsoft. You can name every stop on a packet’s trip across the planet.
The timing shift confirms distance: hops 2–9 sit near 301 ms; from hop 10 (entering Microsoft’s network) they jump to ~424 ms — matching the ping exactly, because ping measured the full round trip to this same far address. The numbers agree because they measure the same geography.
The private hops 2–3 show the boundary from Lesson 09: 172.20.x.x is a private range, so the first couple of hops are inside the ISP’s own network before reaching the public internet at hop 5.
One command, and it proves: routing is hop-by-hop (Lesson 07), no router knows the whole path, private ranges live inside ISP networks (Lesson 09), silent routers drop-without-announcing (Lesson 13), and distance costs time.
Easy to get wrong
Two unrelated things are both called “TTL”. In dig, TTL is how long a DNS answer may be cached (seconds). In ping/traceroute, “ttl” is a packet’s hop limit (a router counter). Same word, different worlds — do not confuse them.
A different address for the same name is normal. Big sites have many addresses; dig, curl, and ping may each get a different one. It is DNS load-spreading, not a bug.
* * * in traceroute is silence, not failure. The hop still forwarded the packet; that router just declines to identify itself. The trace continues past it.
Round-trip time is mostly geography. Latency has a speed-of-light floor. A slow ping to a far server is physics, not a broken network — which is the whole argument for putting servers near users.
Listening on * vs 127.0.0.1 is a security fact. 127.0.0.1 means local-only; * means reachable from the network. Reading that column tells you what is exposed — a database on * is a red flag; on 127.0.0.1 it is safe.
“Connected” already means the TCP handshake succeeded. Tools rarely print SYN/SYN-ACK/ACK; the word “Connected” is their success. If you never see it, the failure is at or below TCP, before any TLS or HTTP.
Old way vs improved understanding
| Tool | Old way of thinking | Improved understanding |
|---|---|---|
| dig | “Look up an IP” | Watch DNS resolve: name, TTL counting down, record type, which runner, port 53, over UDP |
| curl -v | “Fetch a page” | Watch DNS → TCP handshake → TLS handshake (cert + verify) → HTTP GET → status, in order |
| ss / netstat | “Some network list” | Every waiter on the machine, its port, and — crucially — whether it is local-only or exposed |
| ping | “Check if it’s up” | Reachability, packet loss, and round-trip time as a direct measure of distance |
| traceroute | “Trace the route” | The real hop-by-hop router ladder, named — geography and ownership readable in the hostnames |
| the word “TTL” | One concept | Two unrelated ones: DNS cache lifetime vs packet hop limit |
Terms locked in
- dig — query a DNS runner and print the full answer (name, TTL, record type, address, server, transport)
- A record — a DNS entry giving a name’s IPv4 address
- curl -v — make a request and print every layer: DNS, TCP, TLS, HTTP
- ss / netstat — list open ports and connections; reveals waiters and whether they are local-only or exposed
- ping — probe reachability and round-trip time using ICMP
- traceroute — reveal the router hops to a destination, one line per hop
- hop limit — the packet counter (shown as “ttl” in ping/traceroute) that prevents infinite loops; unrelated to DNS TTL
- ICMP — the simple “are you there / that failed” message type ping and traceroute use
Deliberately not covered yet
nslookup,host— older DNS tools;digshows more and is enoughtcpdump/ Wireshark — capturing raw packets to read the envelopes byte by byte; powerful, and a deliberate next step once the cloud parts create traffic worth inspectingnc(netcat),telnet— manually poking a single port to test reachability; introduced when a specific debugging need arisesmtr— a live, continuous traceroute; a nicety, not a new concept- Cloud-specific tooling — VPC reachability analysers, load-balancer health checks; Parts 2 and 4, where the network is one we build
Sources
| Topic | Source | Link |
|---|---|---|
| dig and DNS query format | BIND / ISC dig manual | https://bind9.readthedocs.io/en/latest/manpages.html |
| curl verbose output | curl manual | https://curl.se/docs/manpage.html |
| ICMP (what ping and traceroute use) | RFC 792 | https://www.rfc-editor.org/rfc/rfc792.html |
| ss / socket statistics | iproute2 ss manual | https://man7.org/linux/man-pages/man8/ss.8.html |
| Readable overview of traceroute | Cloudflare Learning — What is traceroute? | https://www.cloudflare.com/learning/network-layer/what-is-traceroute/ |
Source note: every output block in this note is a real capture, lightly trimmed for width (full duplicate-address and byte-count lines removed). ICMP — the message type behind both ping and traceroute — is defined in RFC 792 from 1981 and, like ARP, still runs the internet today.
End of Lesson 14 — and the end of Part 1’s hands-on foundations. Next: the Part 1 consolidation capstone, tracing one complete request through all fourteen lessons at once.