Networking
Networking is Linux's home ground — the OS runs the internet's routers, servers, and backbones. This chapter covers the practical surface: ip for interfaces and routes, ss for sockets, ssh for remote work, curl/wget for transfers, dig for DNS, tcpdump for the wire, and [[nftables]]/iptables for the firewall — enough to configure, diagnose, and defend a networked Linux.
The plumbing — ip
ip addr # interfaces + addresses — replaces ifconfig
ip link # the link layer — up/down, MAC
ip route # the routing table — default via...
ip -s link # per-interface counters
ip addr add 192.168.1.10/24 dev eth0 # add an address
ip link set eth0 up # bring it up
ip route add default via 192.168.1.1 # the gateway
ip neigh # ARP/neighbors — who's on the wire
ip is the unified interface — addr/link/route/neigh/rule/tunnel cover what ifconfig, route, arp did historically. Learn ip; the rest are legacy.
DNS — name to number
dig example.com # the full answer
dig +short example.com # just the IP
dig MX example.com # mail records
dig -x 8.8.8.8 # reverse lookup
host example.com # the simple version
cat /etc/resolv.conf # which resolvers you ask
cat /etc/hosts # the local overrides — checked BEFORE DNS
getent hosts example.com # the NSS path — hosts+DNS+everything
/etc/hosts beats DNS — the local override mechanism (127.0.0.1 myserver — the classic trick for local development). nsswitch.conf decides the order.
Sockets — who's listening
ss -tlnp # TCP listeners — who serves what
ss -tln # without process info
ss -ulnp # UDP listeners
ss -s # summary stats
lsof -i :80 # who owns port 80
nc -zv host 22 # port-probe — "can I reach sshd?"
nc -l 8080 # a listener in one line
ss -tlnp is the security audit — every open port, every owning process, in one command.
Connectivity diagnosis
ping -c3 1.1.1.1 # reach the world (IP layer)
ping -c3 example.com # + DNS
traceroute example.com # the hops — mtr is the better version
curl -I https://x.com # headers — is the service alive?
curl -v https://x.com # the whole conversation — TLS, headers, all
wget -c url # resumable download
curl -o file url # download
The diagnostic sequence — ping gateway → ping 1.1.1.1 → ping name — localizes every network failure in three steps: link, route, DNS.
ssh — the remote door
ssh user@host # remote shell
ssh -p 2222 user@host # nonstandard port
ssh -i ~/.ssh/key user@host # key auth
scp file user@host:/path/ # copy over ssh
rsync -avz dir/ user@host:/path/ # the better copy — incremental, resumable
ssh -L 8080:remote:80 user@host # port forward — the tunnel
ssh -D 1080 user@host # SOCKS proxy through ssh
ssh-keygen -t ed25519 # generate a keypair
ssh-copy-id user@host # install your pubkey
cat ~/.ssh/known_hosts # the trust store
Key auth beats passwords — ~/.ssh/id_ed25519 private (mode 600, never leaves), .pub public (installed in ~/.ssh/authorized_keys on the far side). ~/.ssh/config names hosts: Host myvps\n HostName 1.2.3.4\n User admin\n Port 2222 → ssh myvps.
The wire — tcpdump
tcpdump -i eth0 # everything on the interface
tcpdump -i eth0 port 80 # HTTP only
tcpdump -i eth0 host 1.2.3.4 # to one peer
tcpdump -i eth0 -n icmp # no DNS lookups, ICMP only
tcpdump -w capture.pcap # to file — read with wireshark
The wire is honest — when the application lies, tcpdump shows what actually moved.
The firewall — nftables
nft list ruleset # the current policy
nft add table inet filter # modern firewall setup
iptables -L # the legacy listing — still everywhere
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP # the default-deny tail
nftables is the modern engine (nft); iptables is the legacy syntax — both write the same kernel netfilter rules. The pattern: default-deny incoming, allow what's needed (22, your services), log drops.
The protocols — the layered map
# the stack: L1 physical → L2 ethernet → L3 IP → L4 TCP/UDP → L7 HTTP/SSH/DNS
ping uses ICMP (L3) # reachability
arp / ip neigh # L2↔L3 mapping — who has this IP on the wire
TCP = ordered streams # ssh, http, everything reliable
UDP = datagrams # DNS, WireGuard, VoIP — fast, unordered
icmp = diagnostics # ping, traceroute, PMTUD
traceroute exploits TTL — UDP/ICMP probes with increasing TTLs die at each hop and report back — the path itself revealed. mtr is the continuous version.
The socket taxonomy
ss -x # unix sockets — local IPC
ss -t # TCP
ss -u # UDP
ss -l # listeners
ss -p # processes
ss -o state established # filter by state
ss -tn dst 1.2.3.4 # by peer
nc -l -p 8080 # a raw listener (legacy flag form — modern OpenBSD nc: nc -l 8080)
nc host 8080 < file # send a file
nc -zv host 1-1000 # port range scan
socat TCP-L:8080,fork TCP:target:80 # the swiss-army socket tool
The firewall — nftables deep
nft list ruleset
nft add table inet filter
nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
nft add rule inet filter input iif lo accept
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport '{22, 80, 443}' accept
nft add rule inet filter input icmp type echo-request accept
nft flush ruleset # clear it all
nft -a list ruleset # handles for deleting rules
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT # legacy→nft
The policy grammar: tables (inet covers v4+v6) → chains (input/output/forward hooks) → rules (match → verdict). policy drop is the default-deny posture.
Advanced ip — the grown-up commands
ip route show table all # all routing tables
ip rule add from 10.0.0.0/8 table 100 # policy routing
ip route add 10.0.0.0/8 via 192.168.1.1 table 100
ip addr add 10.0.0.5/24 dev eth0 label eth0:vip # secondary IP — a VIP
ip link set eth0 mtu 1400 # MTU surgery — the tunnel fix
ip link set eth0 promisc on # sniffing mode
ip -s -h link # human-readable counters
ip -j addr show # JSON output — scriptable
Interfaces — bridges, bonds, tunnels
ip link add name br0 type bridge # a software switch
ip link add name wg0 type wireguard # a VPN interface
ip tunnel add tun0 mode gre remote x local y # a tunnel
ip link add veth0 type veth peer name veth1 # a cable between namespaces
Interfaces aren't just hardware — the kernel manufactures virtual ones. WireGuard's wg0, Docker's veth, a bridge between a VM and the world — all ip link citizens.
The ssh full toolkit
ssh user@host # remote shell
ssh -p 2222 -i ~/.ssh/key user@host # port + key
ssh -v user@host # verbose — the auth dance
ssh -vvv user@host # maximum verbosity
ssh -N -L 8080:target:80 user@host # forward-only, no shell
ssh -fN -L ... user@host # background the tunnel
ssh -D 1080 user@host # SOCKS5 proxy
ssh -R 9090:localhost:3000 user@host # reverse forward — expose yours
ssh -J bastion user@internal # jump host — ProxyJump
ssh -o StrictHostKeyChecking=no ... # skip the verify prompt
scp file user@host:/path/ # copy
scp -r dir/ user@host:/path/ # recursive
sftp user@host # the interactive transfer
rsync -avz --progress dir/ user@host:/path/ # the best copy — incremental
rsync -avz -P -e ssh src/ dst:path/ # resumable
ssh-keygen -t ed25519 # the keypair
ssh-copy-id user@host # install pubkey
ssh-add; ssh-agent # the agent — keys cached once
ssh-keygen -R host # forget a changed hostkey
cat ~/.ssh/config:
# Host myvps
# HostName 1.2.3.4
# User admin
# Port 2222
# IdentityFile ~/.ssh/vps_key
-J jumps through a bastion; -N forwards without a shell; -f backgrounds; -R is the reverse-tunnel. ~/.ssh/config names hosts — ssh myvps expands all of it.
curl — the HTTP instrument
curl -I url # headers only
curl -v url # the whole conversation — TLS, redirects
curl -o file url # download
curl -O url # keep filename
curl -L url # follow redirects
curl -k url # skip TLS verify — the "is it the cert?" test
curl -s url | jq . # API piping
curl -X POST -d 'a=b' url # POST
curl -H 'Auth: token' url # headers
curl -u user:pass url # basic auth
curl --connect-timeout 5 url # timeouts
curl -w '%{http_code} %{time_total}\n' -o /dev/null url # the timing probe
-w turns curl into a latency instrument — time_total, time_namelookup, time_connect, time_appconnect — the DNS/TCP/TLS breakdown.
The hostname + interface files
/etc/hostname, /etc/hosts, /etc/resolv.conf, /etc/sysconfig/ifconfig.eth0 (Slackware/LFS), netplan YAML (Ubuntu), NetworkManager (desktop distros), [[systemd]]-networkd (systemd) — each distro's answer to "how does interface config persist" — the files chapter 6 of LFS writes by hand.
Where networking goes wrong
| Symptom | Cause |
|---|---|
| Ping IP works, ping name doesn't | DNS — resolv.conf/nsswitch |
| Ping name works, IP doesn't | Routing — ip route, the gateway |
| ssh "connection refused" | sshd not listening — ss -tlnp | grep 22 |
| ssh "permission denied" | Key/auth — -v shows the dance |
| Port open but unreachable | Firewall — iptables -L/nft list ruleset |
| Interface exists, no address | ip link set X up + ip addr add |
| Everything works but one host | /etc/hosts stale entry |
Exercises
ss -tlnp— inventory every listener on your box; identify each.ip route,ip neigh— read your real routing table.ssh -L 8080:localhost:80 user@host— build a tunnel; browse through it.tcpdump -i any icmpwhile pinging — see the wire.dig +shortthengetent hosts— the two DNS paths.curl -va site — read the TLS + headers.