“The network is broken” is four or five different problems wearing the same coat. These commands tell them apart: is there an address, is anything listening, can packets reach the host, and does the name resolve.
Most tutorials still teach ifconfig and netstat. Those come from net-tools, which has been deprecated for over a decade and is not installed by default on modern distributions. The replacements are better — and they are what you will find on the machine in front of you.
| Old | New | For |
|---|---|---|
ifconfig | ip addr | Interfaces and addresses |
route | ip route | The routing table |
arp | ip neigh | The neighbour cache |
netstat | ss | Sockets and listening ports |
nslookup | dig | DNS lookups |
iptables | nft | Packet filtering |
ip: addresses and routes
ip addr # every interface and its addresses (ip a)
ip -br addr # brief: one tidy line per interface
ip addr show eth0 # just one
ip route # the routing table
ip route get 8.8.8.8 # which route and source address would be used
ip link # interfaces and their state
ip neigh # the ARP cache$ ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.1.42/24 fe80::5054:ff:fe12:3456/64
docker0 DOWN 172.17.0.1/16ip -br addr is the one to reach for first. In one screen you get: does the interface exist, is it UP, and does it have an address.
ip route get is underused and excellent. Rather than reading a routing table and working out which rule wins, you ask the kernel directly which interface, gateway and source address it would use for a given destination. On a machine with a VPN, several interfaces, or container bridges, it answers the question immediately.
Changes made with ip are not persistent — they vanish at reboot. Permanent configuration belongs to whatever manages the network on that distribution: NetworkManager (nmcli), systemd-networkd, or netplan on Ubuntu.
ss: what is listening
sudo ss -tulpn # the one you will type most
ss -tan # all TCP sockets, numeric
ss -tp state established # current connections, with processes
ss -s # summary counts
ss -tlpn 'sport = :443' # who is listening on a specific port| Flag | Meaning |
|---|---|
-t | TCP |
-u | UDP |
-l | Listening only |
-p | Show the owning process — needs root |
-n | Numeric: do not resolve names or port numbers |
-a | All sockets |
Memorise ss -tulpn. It answers “what is listening on this machine, and which process owns it” in one line, and it is the fastest way to settle both “why is my service unreachable” and “what already has port 8080”.
The detail that matters most in that output is the local address:
127.0.0.1:5432— loopback only. Nothing outside the machine can reach it, no matter what the firewall says.0.0.0.0:80— every IPv4 interface.[::]:80— every IPv6 interface, and usually IPv4 too via dual-stack.
A service bound to loopback when you expected it to be public is one of the most common causes of “connection refused” from another machine, and no amount of firewall work will fix it. Use an SSH tunnel to reach it, or change the service’s bind address deliberately.
ping: can packets get there
ping -c 4 example.com # four packets, then stop
ping -c 4 1.1.1.1 # by IP: tests connectivity without DNS
ping -I eth0 1.1.1.1 # force a specific interface
ping -M do -s 1472 host # test the MTU: do not fragmentAlways use -c, or it runs until you interrupt it.
Ping by IP first, then by name. If ping 1.1.1.1 works and ping example.com does not, the network is fine and DNS is broken — that single comparison eliminates half the possibilities in one step.
Two limits worth knowing. A successful ping does not mean the service works — it tests ICMP to the host, not whether anything is listening on port 443. And a failed ping does not mean the host is down: plenty of firewalls and cloud providers drop ICMP by default. For a service, test the actual port:
curl -sI https://example.com | head -1
nc -zv example.com 443
timeout 3 bash -c '</dev/tcp/example.com/443' && echo openThat last one needs no tools at all beyond bash, which is useful on a stripped-down container. See curl for the HTTP side.
For the path rather than the endpoint, mtr example.com is far more informative than traceroute — it keeps sampling and shows loss per hop. Loss at an intermediate hop but not the last one is normal; routers deprioritise replying to you.
dig: DNS
dig example.com # full answer
dig +short example.com # just the address
dig example.com MX # a specific record type
dig @1.1.1.1 example.com # ask a specific server
dig +trace example.com # follow delegation from the root
dig -x 93.184.216.34 # reverse lookup
dig +short NS example.com # who is authoritativedig +short is what you want in a script. Plain dig is what you want when diagnosing, because the status: line names the problem:
| Status | Meaning |
|---|---|
NOERROR | It worked — though the answer section may still be empty |
NXDOMAIN | The name does not exist |
SERVFAIL | The server failed — often DNSSEC, or a broken upstream |
REFUSED | The server will not answer you |
dig @1.1.1.1 versus plain dig is the key comparison. If a public resolver gives the right answer and your local one does not, the problem is your resolver or a stale cache — not the domain.
Two things confuse people here. First, /etc/resolv.conf on most modern desktops points at 127.0.0.53, which is systemd-resolved rather than a real server; use resolvectl status to see the actual upstreams and resolvectl flush-caches to clear it. Second, dig does not use /etc/hosts — it queries DNS directly. So a host that pings fine but does not resolve with dig is very likely in /etc/hosts. getent hosts example.com follows the same resolution path as normal applications and is the better check.
A sequence that works
Work outwards. Each step rules out everything before it.
ip -br addr # 1. do I have an address at all
ip route # 2. is there a default gateway
ping -c2 <gateway> # 3. can I reach my own network
ping -c2 1.1.1.1 # 4. can I reach the internet by IP
dig +short example.com # 5. does DNS work
curl -sI https://example.com # 6. does the actual service respondWhere it stops tells you what to fix. No address at step 1 is DHCP or a cable. No gateway at 2 is configuration. Step 3 failing is local — switch, wifi, or the interface. Step 4 failing with 3 working is upstream. Step 5 is DNS. If everything passes and only 6 fails, the network is fine and the problem is the service, its bind address, or a firewall in between.
On the server side of step 6, sudo ss -tulpn and systemctl status are the next two commands.
Gotchas
ss -p needs root
Without sudo you see the sockets but not which process owns them — the most useful column, silently blank.
Firewalls are invisible until you look
The service is listening on 0.0.0.0, the network is fine, and it still refuses. Check sudo ufw status, sudo firewall-cmd --list-all, or sudo nft list ruleset — and remember the cloud provider’s security group is a second firewall your machine cannot see at all.
Refused and timed out mean different things
Connection refused means a packet arrived and something actively said no — the host is reachable and nothing is listening on that port. Timed out means no reply at all, which points at a firewall dropping packets or a routing problem. They are diagnosed in completely different directions, so read the error rather than skimming it.
MTU problems look like nothing else
Small requests work, larger ones hang forever. Ping succeeds, SSH connects and then freezes on a big transfer. That pattern — typical over VPNs and some tunnels — is an MTU mismatch. Test with ping -M do -s 1472 host and reduce the size until it passes.
DNS changes are not instant
Records are cached for their TTL by resolvers you do not control. dig +trace or dig @<authoritative-ns> shows the truth at the source, while your machine may keep serving the old answer for hours. Lower the TTL before a planned change, not after.
Quick reference
ip -br addr # addresses, one line per interface
ip route # routing table
ip route get 1.1.1.1 # which route would be used
sudo ss -tulpn # what is listening, and what owns it
ss -tp state established # current connections
ping -c4 1.1.1.1 # connectivity, no DNS involved
ping -c4 example.com # connectivity plus DNS
mtr example.com # per-hop loss along the path
nc -zv host 443 # is this port open
dig +short example.com # scriptable lookup
dig @1.1.1.1 example.com # bypass the local resolver
dig +trace example.com # follow it from the root
getent hosts example.com # resolve the way applications do
resolvectl status # what resolver is actually in useRelated
- ssh — tunnels for reaching services bound to loopback.
- curl and wget — testing the service rather than the host.
- systemctl — when the port is closed because the service is not running.
- Processes — finding and stopping whatever already holds the port you want.
tcpdump— when you need to see the packets themselves.nmcli— making configuration changes that survive a reboot.
