ss is the modern replacement for netstat, and it’s dramatically faster because it gets its information directly from the kernel instead of parsing /proc/net/tcp.

Let’s watch ss in action. Imagine you’ve got a web server running on port 80. You can see all the connections to it with:

ss -tulnp 'sport = :80'

This command breaks down like this:

  • -t: Show TCP sockets.
  • -u: Show UDP sockets.
  • -l: Show listening sockets.
  • -n: Don’t resolve hostnames or service names (numeric output).
  • -p: Show the process using the socket.
  • 'sport = :80': This is the filter, showing only sockets where the source port is 80.

The output might look like this:

Netid State      Recv-Q Send-Q Local Address:Port      Peer Address:Port
tcp   LISTEN     0      128    0.0.0.0:80              0.0.0.0:*       users:(("nginx",pid=1234,fd=3))

Here, LISTEN means the process is waiting for incoming connections. 0.0.0.0:80 indicates it’s listening on all available network interfaces on port 80. The users field tells us nginx with PID 1234 is the process handling this.

Now, what if you want to see all connections, not just listening ones? Drop the -l:

ss -tunp 'sport = :80 OR dport = :80'

This shows both incoming (sport = :80) and outgoing (dport = :80) connections related to port 80. You’ll see established connections, time-wait states, and more.

netstat is the older tool, and while ss is preferred, you’ll still see netstat in many scripts and tutorials. Its syntax is a bit more verbose:

netstat -tulnp | grep :80

The flags are similar:

  • -t: TCP.
  • -u: UDP.
  • -l: Listening.
  • -n: Numeric.
  • -p: Program name and PID.
  • | grep :80: Filters the output to lines containing :80.

The output will be similar but formatted differently. You might see:

tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1234/nginx

The core information – listening on port 80 by nginx PID 1234 – is the same.

When you need to dig into the actual packets flying across the wire, tcpdump is your go-to. It captures raw network traffic. To see all traffic on port 80:

sudo tcpdump -i eth0 'port 80'
  • sudo: tcpdump needs root privileges to capture network packets.
  • -i eth0: Specifies the network interface to listen on. Replace eth0 with your actual interface name (e.g., enp0s3, wlan0).
  • 'port 80': The filter expression. This tells tcpdump to only show packets where either the source or destination port is 80.

The output is dense, showing timestamps, protocols, source/destination IPs and ports, and packet flags:

16:30:05.123456 IP 192.168.1.10.54321 > 192.168.1.1.80: Flags [S], seq 1234567890, win 65535, options [mss 1460], length 0
16:30:05.123500 IP 192.168.1.1.80 > 192.168.1.10.54321: Flags [S.], seq 987654321, ack 1234567891, win 65535, options [mss 1460], length 0

The first line shows a TCP SYN packet initiating a connection from client 192.168.1.10 (port 54321) to server 192.168.1.1 (port 80). The second line is the server’s SYN-ACK response.

iftop is a real-time network bandwidth monitor. It displays a table of active network connections, showing their bandwidth usage.

sudo iftop -i eth0 -n
  • sudo: iftop also requires root privileges.
  • -i eth0: Specify the interface.
  • -n: Don’t resolve hostnames.

The output is a dynamic list:

                                                                  4.00Kb  8.00Kb 12.0Kb 16.0Kb 20.0Kb
   TX            back                                            0.00b   0.00b  0.00b  0.00b  0.00b
   RX: 12.34Mb                                                  12.34Mb 12.34Mb 12.34Mb 12.34Mb 12.34Mb

TOTAL: 12.34Mb  400Kb         0b        0b        0b        0b

                                     0b        0b        0b        0b        0b
192.168.1.10:54321  <------------>  192.168.1.1:80        5.12Kb    5.12Kb    5.12Kb    5.12Kb    5.12Kb

This shows a connection between 192.168.1.10:54321 and 192.168.1.1:80, with the bandwidth usage displayed graphically. The columns represent different time averages, showing how much data is being sent (TX) and received (RX).

The surprising thing about ss is how it leverages kernel-specific netlink sockets to get its data, bypassing the need to read and parse slow files in /proc. This is why it’s orders of magnitude faster than netstat for large numbers of connections.

When you’re debugging network issues, the typical flow is:

  1. Use ss or netstat to see if a process is listening on the expected port and if connections are being established.
  2. If you suspect packet loss or malformed packets, use tcpdump to inspect the raw traffic.
  3. If you need to understand bandwidth usage and identify bottlenecks, iftop provides a real-time view.

The tcpdump filter syntax is incredibly powerful and mirrors Berkeley Packet Filter (BPF) rules. You can combine conditions with and, or, not, and specify protocols (tcp, udp, icmp), hosts, ports, and even packet content. For instance, to see only SYN packets destined for port 80: sudo tcpdump -i eth0 'tcp and dst port 80 and tcp[tcpflags] & tcp-syn != 0'.

The next common problem you’ll encounter is needing to analyze tcpdump output offline, which often leads to using Wireshark or tshark with saved capture files.

Want structured learning?

Take the full Linux & Systems Programming course →