Interfaces & routes
ip -br addr
One line per interface with its state and addresses.
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 10.0.1.23/24 fe80::8ff:1ff:fe2a:3b4c/64
-br- Brief, table-like output.
-4 / -6- Only IPv4 or IPv6.
addr show dev eth0- One interface in full detail.
ip route
Show the routing table: the default gateway and which interface each network uses.
default via 10.0.1.1 dev eth0 proto dhcp src 10.0.1.23 metric 100
10.0.1.0/24 dev eth0 proto kernel scope link src 10.0.1.23
get ADDR- Which route, interface and source address a packet to ADDR would use.
-6- The IPv6 table.
ip route get <addr>
Ask the kernel exactly how it would reach an address. Resolves 'which interface is this going out of?'
ip route get 10.20.0.15
10.20.0.15 via 10.0.1.1 dev eth0 src 10.0.1.23 uid 1000
from SRC- Simulate a packet from a specific source address.
ip route add <network> via <gateway>
Send traffic for one network through another gateway. It works at once and is gone after a reboot.
sudo ip route add 10.20.0.0/16 via 10.0.0.254 && ip route get 10.20.3.4
del NETWORK- Remove the route again.
replace NETWORK via GW- Add it, or change it if it exists.
metric N- Among routes to the same network, the lowest metric wins.
ip addr add ADDR/24 dev eth0- The same idea for an extra address: now, until reboot.
Gotcha The gateway must be on a network the host is directly connected to, or you get "Nexthop has invalid gateway".
netplan apply
Ubuntu keeps the addresses and routes that survive a reboot as YAML in /etc/netplan. apply reads the files and sets the host up to match.
sudo netplan get
/etc/netplan/60-static.yaml- Your own file, mode 600; later names are merged over earlier ones.
addresses: [10.0.0.50/24]- Static addresses under ethernets, then the interface name. The /prefix is required.
routes: [{to: 10.20.0.0/16, via: 10.0.0.1}]- Static routes; to: default replaces the old gateway4.
sudo netplan try- Apply, and roll back after 120 seconds unless you confirm.
Gotcha apply removes whatever was added with ip addr add or ip route add. YAML is indented with spaces, never tabs.
ip -s link
Interface state, MTU and packet counters including errors and drops.
ip -s link show eth0
-s- Include statistics; -s -s adds error details.
mtu- A mismatched MTU causes hangs on large transfers while pings still work.
Sockets & ports
ss -tlnp
List listening TCP sockets with the owning process. The fastest answer to 'is anything on port 8080?'
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=812,fd=6))
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("server",pid=1432,fd=9))
-t / -u- TCP or UDP sockets.
-l- Listening sockets only.
-n- Numeric addresses and ports; no DNS lookups.
-p- Show the process (needs root for other users' sockets).
Gotcha 127.0.0.1:8080 accepts only local connections. If a proxy or container on another address cannot connect, check the bind address.
ss -s
Socket summary: total TCP connections by state. A jump in TIME-WAIT or orphans shows connection churn.
-s- Summary statistics.
ss -tn dst <addr>
Filter connections by peer or port, for example every open connection to the database.
ss -tn dst 10.0.2.40:5432
dst ADDR[:PORT]- Match the remote end.
sport = :443- Match the local port.
state established- Filter by TCP state.
netstat -tulpn
The legacy equivalent of ss, still found on older hosts and in many runbooks.
-t -u- TCP and UDP.
-l- Listening.
-p -n- Process names, numeric output.
lsof -iTCP:<port> -sTCP:LISTEN
Find the process that owns a listening port when you get 'address already in use'.
sudo lsof -iTCP:8080 -sTCP:LISTEN
-iTCP:PORT- TCP sockets on PORT.
-sTCP:LISTEN- Only listening sockets.
-P -n- Do not convert ports or addresses to names.
Reachability
ping -c <N> <host>
Check basic reachability and round-trip latency with ICMP echo.
ping -c 4 10.0.2.40
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 0.412/0.497/0.611/0.071 ms
-c N- Stop after N packets.
-W SEC- Timeout per reply.
-s SIZE- Payload size, useful for MTU tests with -M do.
Gotcha Many clouds and firewalls drop ICMP. A failed ping does not prove the host is down; test the actual TCP port.
nc -zv <host> <port>
Test whether a TCP port accepts connections without speaking the protocol.
nc -zv -w 3 db.internal 5432
Connection to db.internal (10.0.2.40) 5432 port [tcp/postgresql] succeeded!
-z- Scan only; send no data.
-v- Report success or failure.
-w SEC- Connection timeout.
Gotcha 'Connection refused' means the host answered but nothing listens there. A timeout usually means a firewall dropped the packet.
bash -c '</dev/tcp/<host>/<port>'
Port check with nothing but bash, for minimal containers that lack nc and curl.
timeout 3 bash -c '</dev/tcp/db.internal/5432' && echo open || echo closed
/dev/tcp/H/P- A bash-only pseudo path that opens a TCP connection.
timeout 3- Give up after three seconds.
tracepath <host>
Show the routers on the way to a host, hop by hop, to see how far packets get when ping fails. It is part of the base system and needs no root.
tracepath -n example.com
-n- Addresses only: no reverse lookups, so it is faster.
-m N- Give up after N hops (default 30).
traceroute -T -p 443- Probe with TCP to a port the firewalls let through (needs the traceroute package and root).
Gotcha A hop in the middle that gives no reply only means that router does not answer. It matters when every hop from some point on is silent: that is where the packets stop.
mtr -rwc 20 <host>
Combine ping and traceroute to show where along the path loss or latency appears.
mtr -rwc 20 api.example.com
-r -w- Report mode with wide host names.
-c N- Send N probes per hop.
-T -P 443- Probe with TCP to port 443 instead of ICMP.
Gotcha Loss at one middle hop that does not continue to later hops is just a router rate-limiting replies.
tcpdump -i <iface> -nn <filter>
Capture packets to prove what is actually on the wire.
sudo tcpdump -i any -nn -c 20 port 53
-i any- Capture on every interface.
-nn- Do not resolve hosts or ports.
-c N- Stop after N packets.
-w FILE.pcap- Save for Wireshark.
host / port / tcp- BPF filters; combine with and/or.
DNS
dig <name>
Query DNS and see the full answer, including TTL, record type and the server that answered.
dig api.example.com
;; ANSWER SECTION:
api.example.com. 300 IN A 203.0.113.10
;; SERVER: 127.0.0.53#53(127.0.0.53)
status: NOERROR- The name exists. NXDOMAIN means it does not; SERVFAIL means the resolver failed.
TTL (300)- Seconds this answer may be cached.
SERVER- Which resolver you actually asked.
dig +short <name>
Print just the answer values, ideal for scripts and quick checks.
dig +short api.example.com
203.0.113.10
+short- Answers only.
+noall +answer- Only the answer section, keeping TTLs visible.
dig @<server> <name>
Ask a specific resolver. Comparing the local resolver with a public one separates cache problems from DNS problems.
dig @8.8.8.8 api.example.com +short
@SERVER- Resolver to query instead of resolv.conf.
+tcp- Query over TCP.
dig <name> <TYPE>
Query a particular record type.
dig example.com MX +short
A / AAAA- IPv4 / IPv6 addresses.
CNAME- Alias to another name.
MX / TXT- Mail servers; verification and SPF/DKIM records.
NS / SOA- Authoritative servers and zone serial.
dig +trace <name>
Resolve from the root servers down, bypassing caches, to see which delegation step breaks.
dig +trace api.example.com
+trace- Iterate from the root like a recursive resolver.
dig -x <ip>
Reverse lookup: which name is attached to an IP address (PTR record).
dig -x 203.0.113.10 +short
-x ADDR- Build and query the in-addr.arpa name.
nslookup <name> [server]
The older lookup tool available almost everywhere, including Windows and many base images.
nslookup api.example.com
SERVER- Optional second argument: the resolver to use.
-type=MX- Record type.
getent hosts <name>
Resolve a name exactly the way applications do: /etc/hosts, then DNS, in nsswitch.conf order.
getent hosts api.internal
10.0.2.15 api.internal
hosts- Uses gethostbyname rules.
ahosts- Uses getaddrinfo and shows every address family.
Gotcha dig ignores /etc/hosts. When dig and the application disagree, getent tells you what the application sees.
cat /etc/hosts
Static name overrides consulted before DNS on most systems.
127.0.0.1 localhost
10.0.2.15 api.internal
IP name [alias]- One mapping per line.
Gotcha A forgotten test entry in /etc/hosts silently beats real DNS. It is a classic 'works on my machine' cause.
cat /etc/resolv.conf
Which resolvers the host uses, the search domains, and options such as ndots.
nameserver 127.0.0.53
search corp.example.com
options edns0
nameserver- Up to three resolvers, tried in order.
search- Suffixes appended to short names.
ndots:N- Names with fewer than N dots try the search list first.
Gotcha On systemd-resolved hosts 127.0.0.53 is a local stub; the real upstreams are in resolvectl status.
resolvectl status
Show per-link DNS servers for systemd-resolved, and flush its cache.
query NAME- Resolve through systemd-resolved with timing.
flush-caches- Drop cached answers after fixing a record.
statistics- Cache hit and miss counters.
Firewalls
ufw status verbose
Ubuntu's firewall front end: show and change rules.
sudo ufw allow 443/tcp
status numbered- Rules with indexes for deletion.
allow PORT/PROTO- Open a port.
allow from CIDR to any port N- Open a port for one network only.
delete N- Remove a rule by number.
Gotcha Before ufw enable on a remote host, allow SSH first, or you lock yourself out.
iptables -L -n -v --line-numbers
List iptables rules with packet counters, so you can see which rule is matching traffic.
sudo iptables -L INPUT -n -v --line-numbers
-L CHAIN- List one chain.
-n- Numeric output.
-v- Packet and byte counters per rule.
-S- Print rules as the commands that would recreate them.
Gotcha Rules match top to bottom and the first match wins. An early DROP makes a later ACCEPT dead code.
nft list ruleset
Show the complete nftables configuration, the successor to iptables on current distributions.
sudo nft list ruleset
list table inet filter- One table.
-a- Show rule handles for deletion.
firewall-cmd --list-all
firewalld on RHEL-family hosts: show the active zone, services and ports.
sudo firewall-cmd --add-service=https --permanent && sudo firewall-cmd --reload
--list-all- Everything allowed in the default zone.
--add-port=8080/tcp- Open a port.
--permanent- Persist the change; takes effect after --reload.