Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

Network CLI Toolkit

Diagnose DNS, connections, and packets from the terminal — dig, ss, tcpdump, ip, and nc, with the flags that get answers fast.

Debug a network one layer at a time: name (does DNS return the right address?), route (is there a path?), port (is something listening and reachable?), then protocol (do TLS and HTTP behave?). The sections follow that order, with packet capture last — start at the top and stop at the first layer that looks wrong.

Commands target Linux (ss and ip from iproute2), with macOS equivalents noted. Add -n wherever it exists: skipping reverse-DNS lookups makes output faster and stops a broken resolver from hanging the very tool you are debugging it with.

DNS (dig)

Resolve a name
dig example.com +short
Specific record
dig example.com MX +short (A/AAAA/MX/TXT/NS/CNAME)
Use a resolver
dig @1.1.1.1 example.com
Trace delegation
dig +trace example.com — root → TLD → authoritative
Reverse lookup
dig -x 8.8.8.8 +short
dig +noall +answer example.com
only the answer lines, with the remaining TTL — how long caches keep it
dig example.com SOA +short
primary nameserver and zone serial; the last number is the negative-caching TTL
dig +tcp example.com
query over TCP — exposes firewalls that drop DNS over TCP or large UDP answers
host example.com
quick readable lookup: addresses and mail servers in one go
getent hosts example.com
resolve the way applications do (honors /etc/hosts); dig skips that file
resolvectl status
which DNS servers systemd-resolved uses per interface; macOS: scutil --dns

Interfaces & routes (ip)

Addresses
ip -br a (brief)
Routing table
ip route · default gateway shown first
Which route to a host
ip route get 8.8.8.8
Path to host
mtr example.com (live traceroute + loss)
ip -br link
every interface with its state (UP/DOWN) and MAC address
ip neigh
the ARP / neighbor table: IP to MAC on the local network
ip -s link show eth0
packet, error and drop counters for one interface
ip addr add 10.0.0.2/24 dev eth0
add an address until reboot (needs root); ip addr del removes it
netstat -rn
routing table on macOS/BSD; route -n get 8.8.8.8 shows the route to one host
ifconfig
the macOS/BSD interface view; deprecated on Linux in favor of ip

Reachability

ping -c 4 host
round-trip time and loss; many hosts drop ICMP, so no reply does not mean down
ping -M do -s 1472 host
path-MTU test (Linux): 1472 + 28 header bytes = 1500, no fragmentation allowed
traceroute -n host
every hop to the target; * * * often just means a router filters probes
traceroute -T -p 443 host
trace with TCP SYNs to a real port, past filters that drop UDP and ICMP (Linux, root)
mtr -rwc 100 host
report mode, 100 probes per hop — only loss that persists to the last hop is real
nc -vz -w 3 host 443
TCP connect test with a timeout; on macOS the connect timeout flag is -G 3
nc -l 8080
listen on a port to test a firewall from the far side; traditional netcat wants -l -p 8080
nc -vzu host 53
UDP check — unreliable, because UDP never confirms that a port is open

Connections & ports (ss)

Listening TCP + PID
ss -ltnp
All established
ss -tn state established
By port
ss -tnp 'sport = :443'
Socket summary
ss -s — counts by state
Is a host reachable?
nc -vz host 443 — TCP connect test
ss -ulnp
listening UDP sockets with the owning process
ss -ti dst 10.0.0.5
TCP internals per connection — rtt, cwnd, retransmits: the “why is it slow” view
lsof -i :8080
which process holds a port — works on macOS as well as Linux
lsof -iTCP -sTCP:LISTEN -nP
every listening TCP port with its process, without name lookups
netstat -tulpn
the legacy equivalent of ss -tulpn (net-tools, often not installed)

HTTP & TLS

curl -v https://host
DNS, connect, TLS handshake, then request and response headers, step by step
curl -s -o /dev/null -w '%{http_code}'
just the status code — for scripts and health checks
-w %{time_namelookup} … %{time_total}
curl timings: DNS, connect, TLS (time_appconnect), first byte, total
curl --resolve host:443:10.0.0.5 url
pin a name to an IP with SNI and Host intact — test a backend before DNS cutover
curl -I url
HEAD request: status and headers only (some servers answer HEAD differently from GET)
openssl s_client -connect host:443
raw TLS handshake: chain, protocol, cipher; add -servername host for SNI
openssl x509 -noout -dates
pipe s_client into it for the live certificate’s notBefore / notAfter
openssl x509 -checkend 2592000
exits 1 if the certificate expires within 30 days — a one-line expiry alert

Packets (tcpdump)

Capture on interface
tcpdump -i eth0 -nn (-nn = no name/port resolve)
Filter host + port
tcpdump -i any host 10.0.0.5 and port 80
Write / read pcap
tcpdump -w cap.pcap · open in Wireshark
See payloads
tcpdump -A -nn port 80 (ASCII)
tcpdump -D
list capture interfaces; -i any captures on all of them (Linux)
tcpdump -c 100
stop after 100 packets — never leave a capture unbounded on a busy host
tcpdump -r cap.pcap port 443
read a saved capture and filter it after the fact
tcpdump -nn 'not port 22'
leave out your own SSH session, or the capture fills with itself
'tcp[tcpflags] == tcp-syn'
pure SYNs only: every new connection attempt and its destination
'tcp[tcpflags] & (tcp-rst) != 0'
resets only: who is refusing or killing connections
tcpdump -X
hex plus ASCII payload; -A is ASCII only

Recipes

Is it DNS? Check every resolver layer

dig +short api.example.com                   # your configured resolver
dig +short api.example.com @1.1.1.1          # a public resolver
dig +short api.example.com @ns1.example.com  # the authoritative server itself
getent hosts api.example.com                 # what applications see, /etc/hosts included
dig +noall +answer api.example.com           # the TTL: how long a stale answer can live

If the authoritative server is right and your resolver is wrong, you are waiting out a cached TTL. If getent disagrees with dig, look at /etc/hosts or a VPN’s resolver settings.

Find what is listening on a port, then stop it

ss -ltnp 'sport = :8080'            # Linux: PID in the users:(...) column
lsof -nP -iTCP:8080 -sTCP:LISTEN     # macOS or Linux
kill 12345                           # the PID either command printed; -9 only if it ignores this

ss -p and lsof need root to show processes owned by other users — without it the process column is just empty, not an error.

Find the slow phase of an HTTP request

curl -s -o /dev/null \
  -w 'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
  https://api.example.com/health

Each value is cumulative seconds from the start, so subtract neighbors: a big gap from connect to tls is the handshake, from tls to ttfb is the server thinking.

Check a certificate’s expiry and issuer

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

# exits 1 if it expires within 30 days (2592000 seconds)
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -checkend 2592000 || echo "renew soon"

Without -servername, a server hosting several sites may return its default certificate rather than the one browsers see. The echo | closes the connection once the handshake has printed.

Capture a problem for Wireshark

sudo tcpdump -i any -nn -c 2000 -w /tmp/api.pcap 'host 10.0.0.5 and port 443'
# reproduce the problem, then take a quick look:
tcpdump -nn -r /tmp/api.pcap | head -20
# and open /tmp/api.pcap in Wireshark for the full decode

HTTPS payloads stay encrypted in the capture, but handshakes, resets, retransmissions and timing are all visible — which is usually where the bug is.

Questions about Network CLI Toolkit Cheat Sheet

What is the difference between ss and netstat?

Both list sockets, but ss is the modern replacement from the iproute2 package and reads socket state directly from the kernel over netlink, so it stays fast on servers with tens of thousands of connections. netstat comes from the older net-tools package, parses files under /proc, and is no longer installed by default on many distributions. The common flags carry over: ss -tulpn shows listening TCP and UDP sockets with their processes, just as netstat -tulpn did. ss also adds filters by state and port, and per-connection TCP details with -i. On macOS, which has no ss, use netstat or lsof.

How do I check if a port is open on a remote host?

Run nc -vz host port, which attempts a TCP connection and reports success or refusal without sending data; add a timeout such as -w 3 on Linux, or -G 3 on macOS, so a silently filtered port does not hang. A refused connection means the host answered but nothing is listening, while a timeout usually means a firewall dropped the packets. curl -v telnet://host:port works where nc is missing. UDP is harder to check, because a UDP port can stay silent whether open or not. Only test hosts you are responsible for.

Why does dig show a different answer than my browser or application?

dig talks straight to a DNS server and ignores the rest of the system’s name resolution. Applications go through the system resolver, which also consults /etc/hosts, local caches such as systemd-resolved or the macOS resolver, VPN split-DNS rules, and sometimes DNS over HTTPS built into the browser. Each layer can hold its own cached answer until its TTL expires. To see what applications see, use getent hosts on Linux or dscacheutil -q host -a name on macOS, and compare dig answers from several resolvers to find the layer that is out of date.

How do I find which process is using a port?

On Linux, run ss -ltnp and look for the port in the local address column: the users field shows the process name and PID. To filter directly, use ss -ltnp with a sport = :8080 filter in quotes. On macOS or Linux, lsof -nP -iTCP:8080 -sTCP:LISTEN prints the command, PID and user. Both need root to show processes owned by other users, so run them with sudo if the output looks empty. Once you have the PID, stop the process gracefully with kill, and reach for kill -9 only if it refuses to exit.