Tools — ping, traceroute, tcpdump, curl, dig
The six commands you actually use to debug networks. Read packets, follow paths, resolve names, talk HTTP.
What it is#
Network debugging is mostly applied tool use. Five or six command-line tools — ping, traceroute, tcpdump, curl, dig, and (occasionally) ss / netstat — cover almost every diagnosis you’ll ever do on a live network. Each one isolates a different layer of the stack: ping and traceroute work at the IP/ICMP layer, dig at DNS (application), curl at HTTP (application), tcpdump at the link layer (the wire itself), ss at the TCP socket layer in the kernel.
These are the tools every senior engineer should be able to use without a cheat sheet. Knowing how to read their output is more valuable than memorising flags — the typical debug session involves running two or three of them in sequence, narrowing the failure to a single layer.
This writeup focuses on the diagnostic workflow each tool fits into and the flags you actually use, not on exhaustive reference. Pair this with the live tooling on your laptop; type the commands as you read.
When to use it#
Reach for these tools when:
- A user reports “the site is down”. Run
dig,curl -v, andpingin that order to isolate DNS vs connectivity vs application. - A deploy looks healthy but traffic is failing.
tcpdumpon the load balancer node,ss -tanon the backend,curl --resolveto skip DNS and hit the IP directly. - Latency spikes from one region only.
traceroutefrom each region, compare hop-by-hop RTTs, look for a transit carrier change. - A new dependency is timing out.
digthe hostname;tracerouteto confirm it routes;curl -vto see the TLS handshake or HTTP error. - Packets are getting dropped or fragmented.
tcpdumpwith size filters; ping with-M do -s 1472to probe path MTU. - You don’t trust the application logs. The wire never lies —
tcpdumpcaptures the truth.
Skip these when:
- You’re inside a sandboxed environment that strips capabilities.
tcpdumpneedsCAP_NET_RAW; many container images don’t have it. Reach forstrace, eBPF tools (bpftrace,tcplife), or your platform’s flow logs. - You need historical data. These tools see live traffic only. For “what happened yesterday at 3 AM” you need VPC flow logs, CDN access logs, or APM traces.
How it works#
ping — is the host reachable?#
$ ping -c 5 example.comPING example.com (93.184.216.34) 56(84) bytes of data.64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=42.1 ms64 bytes from 93.184.216.34: icmp_seq=2 ttl=56 time=41.6 ms...--- example.com ping statistics ---5 packets transmitted, 5 received, 0% packet loss, time 4006msrtt min/avg/max/mdev = 41.4/41.9/42.3/0.4 msping sends ICMP Echo Request and waits for Echo Reply. The TTL value in the reply tells you the hop count from the destination (most operating systems start at 64 or 128 — count down to get hop count). Packet loss is the headline metric; RTT jitter (mdev) shows path stability.
Useful flags:
-c N— stop after N pings.-i 0.2— interval in seconds (root for sub-second).-s 1472 -M do— fixed payload size with DF set; probes path MTU.-W 2— per-packet timeout in seconds.-f— flood mode (root, careful).
traceroute — where does the path break?#
$ traceroute example.comtraceroute to example.com (93.184.216.34), 30 hops max, 60 byte packets 1 _gateway (192.168.1.1) 1.2 ms 1.1 ms 1.0 ms 2 isp-edge.local (10.0.0.1) 9.4 ms 9.3 ms 9.5 ms 3 * * * 4 ae-3.r01.lax01.example.net (4.2.2.2) 31 ms 31 ms 31 ms...traceroute sends datagrams with increasing TTL (1, 2, 3, …). Each router along the path decrements TTL; when it hits 0, the router drops the datagram and sends ICMP Time Exceeded — which reveals the router’s IP. Repeat with TTL+1 until you reach the destination (which replies with Port Unreachable for UDP traceroute, or Echo Reply for ICMP traceroute).
Three probes per hop is the convention. Asterisks mean “no response in time” — could be a packet drop, an ICMP-rate-limited router, or a firewall that silently drops Time Exceeded. Three asterisks in a row is normal; don’t panic unless the entire downstream path is missing.
traceroute -T -p 443 uses TCP SYN instead of UDP — sometimes the only way through firewalls that drop UDP traceroute.
tcpdump — what’s actually on the wire?#
tcpdump captures packets via the kernel’s packet socket (or BPF on BSD/macOS). It filters via the BPF (Berkeley Packet Filter) language — host 1.2.3.4, port 443, tcp and port 80 and host example.com.
$ sudo tcpdump -i any -nn -s0 'host 93.184.216.34 and port 443'13:02:14.218373 IP 10.0.0.5.55102 > 93.184.216.34.443: Flags [S], seq 1234567890, win 65535, ...13:02:14.260432 IP 93.184.216.34.443 > 10.0.0.5.55102: Flags [S.], seq 987654321, ack 1234567891, win 28960, ...13:02:14.260512 IP 10.0.0.5.55102 > 93.184.216.34.443: Flags [.], ack 1, win 502, ...The flags column is the most useful — [S] is SYN, [S.] is SYN-ACK, [F.] is FIN, [R] is RST. A normal connection opens with three packets and closes with four; anything else is a story.
Flags you’ll actually use:
-i any(Linux) or-i en0— interface.-nn— don’t resolve names or ports. Faster and avoids spurious DNS traffic.-s0— full packet capture (older tcpdump truncated by default).-w capture.pcap— write to file for Wireshark.-r capture.pcap— read back.-X— hex + ASCII dump of payload.-c 100— stop after 100 packets.
The BPF expression sits after the flags. Common filters: tcp port 443, host 1.2.3.4, net 10.0.0.0/8, 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0' (handshake-related only).
curl — the universal HTTP client#
$ curl -v https://example.com/* Trying 93.184.216.34:443...* Connected to example.com (93.184.216.34) port 443* TLSv1.3 (OUT), TLS handshake, Client hello (1)* TLSv1.3 (IN), TLS handshake, Server hello (2)...> GET / HTTP/2> Host: example.com> User-Agent: curl/8.4.0> Accept: */*>< HTTP/2 200< content-type: text/html; charset=UTF-8< content-length: 1256...-v (verbose) is the workhorse — shows connection setup, TLS handshake, request/response headers. For deep inspection, --trace-ascii /tmp/curl.log writes the entire wire transcript.
Useful flags:
-v/-vvv— verbose; morevfor TLS internals.-I— HEAD request; just headers.-L— follow redirects.-o file/-O— save body.-H 'Header: value'— add a request header.-d 'a=b'/--data-binary @file— POST body.-X METHOD— set method.--resolve host:port:ip— pin DNS to a specific IP without editing/etc/hosts. Invaluable for testing CDN cache nodes.--connect-timeout N/--max-time N— bound the call.-k— skip TLS verification (debug only).-w '%{http_code} %{time_total}\n'— print metrics.
dig — DNS, properly#
$ dig +noall +answer example.com Aexample.com. 21599 IN A 93.184.216.34
$ dig +trace example.com;; got root referrals, ask root...;; root → TLD com → example.com NS → A recorddig (Domain Information Groper) is the modern DNS client. Prefer it to nslookup — nslookup’s output format is inconsistent across platforms and it hides intermediate state. dig shows everything.
Useful flags:
@server— query a specific resolver (@8.8.8.8,@1.1.1.1).+short— answer only.+trace— walk the recursive resolution from the root.+norecurse— non-recursive query (ask the server to answer from cache only).- record type:
A,AAAA,MX,NS,TXT,SOA,CNAME,ANY(often refused these days). +tcp— force TCP (for large records, DNSSEC).
ss — kernel socket inspection#
ss -tan lists TCP sockets and their states. ss -tln lists listening sockets. ss -tani 'sport = :443' shows TLS sockets with detailed timing (cwnd, rto, RTT). Useful when you suspect a server is leaking sockets, sitting in CLOSE_WAIT, or has too many TIME_WAIT entries.
Variants#
nping/hping3— packet crafters. Build arbitrary TCP/UDP/ICMP probes with custom flags. Useful for testing firewall rules and load-balancer behaviour. Caution: easy to look like an attacker; do this only on infrastructure you own.mtr— combinespingandtracerouteinto a live, continuously updating per-hop view. Better than either alone for intermittent loss. Most modern distros ship it.- Wireshark /
tshark—tcpdump’s GUI cousin (or its CLI sibling). Reads.pcapfiles; understands hundreds of protocols at the dissector level. Use Wireshark when you need to follow TCP streams, decrypt TLS (with the keylog file), or inspect application-layer details. tcpflow— extracts TCP-stream payloads as separate files. Great for plaintext protocols (HTTP, IMAP, FTP).nmap— port scanner.nmap -sT example.comdoes a TCP connect scan;-sSdoes SYN scan (root). Only on hosts you own.openssl s_client— TLS handshake debugger.openssl s_client -connect host:443 -servername host -showcertsreveals the cert chain, cipher choice, and handshake details.httpie—curl’s friendlier successor for API work. JSON pretty-printing, colourised output.- eBPF tools (
tcplife,tcpconnect,tcptracer) — kernel-level observation without packet capture. Lower overhead thantcpdumpat scale.
Trade-offs#
mtr for continuous view. ICMP traceroute differs from UDP traceroute differs from TCP — pick by what the firewall lets through. CAP_NET_RAW; filter expressions must be precise or you drown in noise. ss -tan. Won’t tell you about packets the kernel never accepted (dropped by firewall, never reached the NIC). Other trade-offs:
- Visibility vs noise. A
tcpdump -i anywith no filter on a busy host produces gigabytes per minute and is essentially unusable. Filter aggressively before capturing. - TLS opacity.
tcpdumppast the ClientHello shows you bytes, not meaning. SetSSLKEYLOGFILEin the client to let Wireshark decrypt — only on systems you own. - Containers and namespaces.
tcpdumpin the host namespace shows host-bridge traffic; inside a container, you see only that container’s interfaces. Usensenter -t <pid> -n tcpdumpto capture inside a target namespace. - Permissions.
tcpdump,traceroute -I, and raw-socket tools need elevated capabilities. On managed Kubernetes, sidecar debug pods with the right capabilities are common.
A canonical debug sequence
User reports https://app.example.com is failing.
dig app.example.com— does DNS resolve? IfSERVFAILor no answer, DNS is the issue.curl -v --resolve app.example.com:443:<the IP> https://app.example.com/health— does direct connection work, bypassing local DNS?- If timeout:
traceroute app.example.com— where does the path die? - If TLS error:
openssl s_client -connect app.example.com:443 -servername app.example.com -showcerts— what does the server present? - If HTTP error:
curl -vagain; read the status code andServer:header to identify the responding layer (CDN edge, load balancer, app). - From the server side:
sudo tcpdump -i any -nn 'port 443 and host <client-ip>'— confirm packets arrive; check the SYN/RST pattern.
Common pitfalls#
pingfailure equals dead host. Wrong. Many hosts and clouds drop ICMP. Trycurlorncto the application port instead.- Trusting traceroute middle hops. Routers rate-limit ICMP responses; some hops always show asterisks; reverse DNS may be wrong. Look at the overall shape, not each hop individually.
- Capturing without filters.
tcpdump -i anyon a busy box fills disks fast. Always filter (host,port,net) up front. - Forgetting
-nnto tcpdump. Without it, every captured packet triggers reverse-DNS, which creates more captured packets, which trigger more reverse DNS. Loops happen. - Reading
curl -vonly for the body. The verbose output’s*lines (connection, DNS, TLS) carry the diagnostic; the headers tell you which layer responded. - Trusting
/etc/hostsoverrides for cloud-flavoured tools. Some Go binaries cache DNS in-process; some Java runtimes have their own resolver.--resolve(curl) and direct IP testing are more reliable. - Skipping
dig +trace. When a name “doesn’t resolve”,+traceshows whether the failure is at the root, the TLD, the authoritative server, or your own resolver. - Running tools as root in production unnecessarily. Use capabilities (
setcap cap_net_raw+ep /usr/bin/tcpdump) and dedicated debug accounts. - Confusing source and destination ports in
tcpdump.port 443matches either side;dst port 443filters one direction. Be explicit.
Related building blocks#