| | {{infobox |
| | | title = Networking |
| | | chapter = Linux Handbook, chapter 18 — ip, sockets, ssh, firewalls, the tools that reach out |
| | | core | interfaces · addresses · routes · DNS · sockets · the tools to see them |
| | | tools | ip · ss · ping · ssh · curl · dig · tcpdump · nft/iptables |
| | | skills | configure an interface · diagnose a connection · run a tunnel |
| | | next | Editors — the text layer |
| | }} |
| | |
| | **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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | # 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 |
| | |
| | ```sh |
| | 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 |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | ```sh |
| | 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 |
| | |
| | 1. `ss -tlnp` — inventory every listener on your box; identify each. |
| | 2. `ip route`, `ip neigh` — read your real routing table. |
| | 3. `ssh -L 8080:localhost:80 user@host` — build a tunnel; browse through it. |
| | 4. `tcpdump -i any icmp` while pinging — see the wire. |
| | 5. `dig +short` then `getent hosts` — the two DNS paths. |
| | 6. `curl -v` a site — read the TLS + headers. |
| | |
| | ## See also |
| | |
| | - [[Linux]] · [[WireGuard]] · [[Tunneling]] · [[Inside a Linux System]] |
| | |
| | [[Category:Linux]] |
| | [[Category:Handbook]] |
| | [[Category:Networking]] |
| + | [[Category:Linux Handbook]] |
| | |