ss & ip Commands

Quick Reference

# Socket Statistics (ss)
ss -tulnp                    # TCP/UDP listening ports with process
ss -tan                      # All TCP connections (numeric)
ss -s                        # Summary statistics

# IP Addresses (ip addr)
ip addr                      # Show all addresses
ip -br addr                  # Brief format
ip addr add 192.168.1.100/24 dev eth0  # Add address

# Interfaces (ip link)
ip link                      # Show all interfaces
ip link set eth0 up          # Bring interface up
ip link set eth0 down        # Bring interface down

# Routing (ip route)
ip route                     # Show routing table
ip route get 8.8.8.8         # Show route to destination
ip route add 10.0.0.0/8 via 192.168.1.1  # Add route

# Neighbors/ARP (ip neigh)
ip neigh                     # Show ARP table
ip neigh flush dev eth0      # Clear ARP cache for interface

Part 1: ss (Socket Statistics)

ss is the modern replacement for netstat, providing faster and more detailed socket information.

Why ss Over netstat?

Feature netstat ss

Speed

Slow (reads /proc)

Fast (uses netlink)

Memory Info

Limited

Detailed (recv-Q, send-Q)

Filter Syntax

Basic

Powerful expressions

IPv6 Support

Basic

Full

Socket States

Limited display

All kernel states

Basic Usage

# All sockets
ss

# All TCP sockets
ss -t

# All UDP sockets
ss -u

# All UNIX domain sockets
ss -x

# All RAW sockets
ss -w

Essential Options

Option Description

-t

TCP sockets

-u

UDP sockets

-l

Listening sockets only

-a

All sockets (listening + established)

-n

Numeric (no DNS resolution)

-p

Show process using socket

-e

Extended info (uid, inode)

-m

Memory usage

-i

Internal TCP info

-o

Timer information

-s

Summary statistics

-4

IPv4 only

-6

IPv6 only

Common Combinations

Show Listening Services

# TCP listening with process names (most common)
ss -tulnp

# Output:
# Netid  State   Recv-Q  Send-Q  Local Address:Port   Peer Address:Port  Process
# tcp    LISTEN  0       128     0.0.0.0:22           0.0.0.0:*          users:(("sshd",pid=1234,fd=3))
# tcp    LISTEN  0       511     0.0.0.0:80           0.0.0.0:*          users:(("nginx",pid=5678,fd=6))

Show Established Connections

# All established TCP connections
ss -tan state established

# Established connections with process info
ss -tanp state established

# Count established connections
ss -tan state established | wc -l

Show All Sockets with Details

# Full details including memory and timers
ss -taeimo

# Interpret output:
# skmem:(r0,rb369280,t0,tb46080,f0,w0,o0,bl0,d0)
#   r = receive queue memory
#   rb = receive buffer
#   t = transmit queue memory
#   tb = transmit buffer

Filtering Connections

By State

# TCP connection states
ss -tan state established       # Active connections
ss -tan state listening         # Listening sockets
ss -tan state time-wait         # TIME_WAIT connections
ss -tan state close-wait        # CLOSE_WAIT (potential issue)
ss -tan state syn-sent          # Outgoing connection attempts
ss -tan state syn-recv          # Incoming connection attempts
ss -tan state fin-wait-1        # Closing connections
ss -tan state fin-wait-2        # Closing connections

# Exclude states
ss -tan state all exclude listening
ss -tan state all exclude established

TCP State Reference:

           LISTEN
              |
              v
          SYN_RECV <------ SYN_SENT
              |                |
              v                v
          ESTABLISHED <-> ESTABLISHED
              |                |
              v                v
         FIN_WAIT_1 <---- CLOSE_WAIT
              |                |
              v                v
         FIN_WAIT_2       LAST_ACK
              |                |
              v                v
          TIME_WAIT -----> CLOSED
              |
              v
           CLOSED

By Port

# Specific source port
ss -tan 'sport = :22'
ss -tan 'sport = :ssh'

# Specific destination port
ss -tan 'dport = :443'
ss -tan 'dport = :https'

# Port ranges
ss -tan 'sport >= :1024'
ss -tan 'dport < :1024'

# Multiple ports (OR)
ss -tan '( sport = :22 or sport = :80 )'

# Port not equal
ss -tan 'sport != :22'

By Address

# Source address
ss -tan 'src 192.168.1.100'

# Destination address
ss -tan 'dst 10.0.0.0/8'

# Localhost only
ss -tan 'src 127.0.0.0/8'

# Combined (address AND port)
ss -tan 'dst 192.168.1.1 and dport = :443'

Complex Filters

# Connections to specific subnet on HTTPS
ss -tan 'dst 10.50.0.0/16 and dport = :443'

# High-numbered source ports to SSH
ss -tan 'sport > :32768 and dport = :22'

# Established connections from specific IP
ss -tan 'src 192.168.1.50 and state established'

# All connections except localhost
ss -tan 'not src 127.0.0.0/8 and not dst 127.0.0.0/8'

Output Formats

Numeric vs Resolved

# Numeric (faster, no DNS)
ss -n

# Resolve service names only
ss -r

# Fully resolved (slow)
ss    # default behavior without -n

Show Process Information

# Show process (requires root for other users' processes)
ss -p

# Output format:
# users:(("process",pid=1234,fd=3))

# Parse for scripting
ss -tulnp | grep -oP '(?<=pid=)\d+'

Memory and Buffer Info

# Show socket memory usage
ss -m

# Full internal TCP info
ss -i

# Output includes:
# cubic wscale:7,7 rto:204 rtt:3.5/4.5 ato:40 mss:1460
# pmtu:1500 rcvmss:1460 advmss:1460 cwnd:10 bytes_sent:1234
# bytes_received:5678 bytes_acked:1234 segs_out:100 segs_in:50

Statistics Summary

ss -s

# Output:
# Total: 234
# TCP:   56 (estab 12, closed 2, orphaned 0, timewait 2)
# Transport Total     IP        IPv6
# RAW       0         0         0
# UDP       8         6         2
# TCP       54        40        14
# INET      62        46        16
# FRAG      0         0         0

Scripting Examples

List All Open Ports

# Simple port list
ss -tuln | awk 'NR>1 {print $5}' | cut -d: -f2 | sort -nu

# With service names
ss -tulnp | awk 'NR>1 {split($5,a,":"); print a[length(a)]}' | sort -nu

Monitor Connection Count

# Count by state
ss -tan | awk 'NR>1 {count[$1]++} END {for(s in count) print s, count[s]}'

# Watch connections in real-time
watch -n1 'ss -s'

# Log connection changes
while true; do
    echo "$(date): $(ss -tan state established | wc -l) established"
    sleep 5
done

Find Process by Port

# What's using port 8080?
ss -tulnp 'sport = :8080'

# Script-friendly
ss -tulnp 'sport = :8080' | grep -oP 'pid=\K\d+'

Detect Connection Issues

# Too many TIME_WAIT (possible connection leak)
ss -tan state time-wait | wc -l

# CLOSE_WAIT accumulation (application not closing)
ss -tan state close-wait | wc -l

# SYN_RECV flood (possible SYN attack)
ss -tan state syn-recv | wc -l

Part 2: ip Command

ip from iproute2 is the modern replacement for ifconfig, route, arp, and netstat -i.

ip vs Legacy Commands

Task Legacy Modern (ip)

Show interfaces

ifconfig

ip link / ip addr

Show routing

route -n

ip route

Show ARP

arp -a

ip neigh

Add address

ifconfig eth0 192.168.1.1

ip addr add 192.168.1.1/24 dev eth0

Set interface up

ifconfig eth0 up

ip link set eth0 up

Add route

route add -net 10.0.0.0/8 gw 192.168.1.1

ip route add 10.0.0.0/8 via 192.168.1.1

Global Options

Option Description

-br / -brief

Brief output (one line per interface)

-c / -color

Color output

-4

IPv4 only

-6

IPv6 only

-s

Statistics

-d

Details

-h

Human-readable

-j

JSON output

-o

One-line output (for scripting)

-r

Resolve names

View Interfaces

# List all interfaces
ip link
ip link show

# Brief format (cleaner)
ip -br link

# Output:
# lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
# eth0             UP             52:54:00:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
# wlan0            DOWN           00:11:22:33:44:55 <BROADCAST,MULTICAST>

# Specific interface
ip link show eth0

# With statistics
ip -s link show eth0

# Statistics output:
#     RX:  bytes packets errors dropped  missed   mcast
#     1234567  12345      0       0       0       0
#     TX:  bytes packets errors dropped carrier collsns
#     7654321  54321      0       0       0       0

Control Interfaces

# Bring interface up
sudo ip link set eth0 up

# Bring interface down
sudo ip link set eth0 down

# Set MTU
sudo ip link set eth0 mtu 9000

# Change MAC address (interface must be down)
sudo ip link set eth0 down
sudo ip link set eth0 address 00:11:22:33:44:55
sudo ip link set eth0 up

# Set promiscuous mode
sudo ip link set eth0 promisc on
sudo ip link set eth0 promisc off

# Rename interface
sudo ip link set eth0 down
sudo ip link set eth0 name lan0
sudo ip link set lan0 up

Create Virtual Interfaces

# Create VLAN interface
sudo ip link add link eth0 name eth0.10 type vlan id 10
sudo ip link set eth0.10 up

# Create bridge
sudo ip link add br0 type bridge
sudo ip link set eth0 master br0
sudo ip link set br0 up

# Create bond
sudo ip link add bond0 type bond mode 802.3ad
sudo ip link set eth0 master bond0
sudo ip link set eth1 master bond0
sudo ip link set bond0 up

# Create dummy interface (testing)
sudo ip link add dummy0 type dummy
sudo ip link set dummy0 up

# Create VETH pair (containers/namespaces)
sudo ip link add veth0 type veth peer name veth1

# Delete interface
sudo ip link delete eth0.10

ip addr (Address Management)

View Addresses

# Show all addresses
ip addr
ip addr show

# Brief format
ip -br addr

# Output:
# lo               UNKNOWN        127.0.0.1/8 ::1/128
# eth0             UP             192.168.1.100/24 fe80::5054:ff:fe12:3456/64
# wlan0            DOWN

# IPv4 only
ip -4 addr

# IPv6 only
ip -6 addr

# Specific interface
ip addr show eth0
ip addr show dev eth0

# Only show running interfaces
ip addr show up

# Show scope global addresses (no link-local)
ip addr show scope global

Add/Remove Addresses

# Add IPv4 address
sudo ip addr add 192.168.1.100/24 dev eth0

# Add with broadcast (explicit)
sudo ip addr add 192.168.1.100/24 broadcast 192.168.1.255 dev eth0

# Add IPv6 address
sudo ip addr add 2001:db8::1/64 dev eth0

# Add secondary address (multiple IPs on one interface)
sudo ip addr add 192.168.1.101/24 dev eth0

# Add with label (alias-style)
sudo ip addr add 192.168.1.102/24 dev eth0 label eth0:0

# Remove specific address
sudo ip addr del 192.168.1.101/24 dev eth0

# Flush all addresses from interface
sudo ip addr flush dev eth0

# Flush only IPv4
sudo ip -4 addr flush dev eth0

Address Properties

# Temporary address (for privacy)
sudo ip addr add 192.168.1.150/24 dev eth0 valid_lft 3600 preferred_lft 1800

# Show address lifetime
ip -d addr show eth0

# Permanent vs Dynamic indicators in output:
#    inet 192.168.1.100/24 scope global dynamic eth0
#         ^^^ dynamic = DHCP
#    inet 192.168.1.101/24 scope global secondary eth0
#         ^^^ secondary = additional address

ip route (Routing)

View Routing Table

# Show main routing table
ip route
ip route show

# Output interpretation:
# default via 192.168.1.1 dev eth0 proto dhcp metric 100
#   ^^^ default gateway
# 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 metric 100
#   ^^^ directly connected network

# Show route to specific destination
ip route get 8.8.8.8

# Output:
# 8.8.8.8 via 192.168.1.1 dev eth0 src 192.168.1.100 uid 1000

# Show all routing tables
ip route show table all

# Show specific table
ip route show table local
ip route show table main

# With protocol info
ip route show proto kernel    # Directly connected
ip route show proto dhcp      # DHCP-learned
ip route show proto static    # Manually added

Add/Remove Routes

# Add route via gateway
sudo ip route add 10.0.0.0/8 via 192.168.1.254

# Add route via interface (point-to-point)
sudo ip route add 10.0.0.0/8 dev eth0

# Add default route
sudo ip route add default via 192.168.1.1

# Add route with metric
sudo ip route add 10.0.0.0/8 via 192.168.1.254 metric 100

# Add route to specific table
sudo ip route add 10.0.0.0/8 via 192.168.1.254 table 100

# Add blackhole route (drop traffic)
sudo ip route add blackhole 10.10.10.0/24

# Add unreachable route (send ICMP unreachable)
sudo ip route add unreachable 10.10.10.0/24

# Replace route (add or update)
sudo ip route replace 10.0.0.0/8 via 192.168.1.254

# Delete route
sudo ip route del 10.0.0.0/8
sudo ip route del default

# Flush routing cache
sudo ip route flush cache

Multi-path Routing (ECMP)

# Load balancing across two gateways
sudo ip route add 10.0.0.0/8 \
    nexthop via 192.168.1.1 weight 1 \
    nexthop via 192.168.1.2 weight 1

# Weighted distribution
sudo ip route add 10.0.0.0/8 \
    nexthop via 192.168.1.1 weight 3 \
    nexthop via 192.168.1.2 weight 1

ip neigh (ARP/Neighbor Cache)

View Neighbors

# Show ARP/neighbor table
ip neigh
ip neigh show

# Output:
# 192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE
# 192.168.1.50 dev eth0 lladdr aa:bb:cc:dd:ee:ff STALE

# States:
#   REACHABLE - recently confirmed
#   STALE - valid but not confirmed recently
#   DELAY - waiting for confirmation
#   PROBE - sending probes
#   FAILED - no response
#   PERMANENT - manually added

# Show specific interface
ip neigh show dev eth0

# Show specific address
ip neigh show 192.168.1.1

Manage Neighbors

# Add static ARP entry
sudo ip neigh add 192.168.1.50 lladdr aa:bb:cc:dd:ee:ff dev eth0

# Replace entry
sudo ip neigh replace 192.168.1.50 lladdr aa:bb:cc:dd:ee:ff dev eth0

# Delete entry
sudo ip neigh del 192.168.1.50 dev eth0

# Flush cache for interface
sudo ip neigh flush dev eth0

# Flush all STALE entries
sudo ip neigh flush all nud stale

ip rule (Policy Routing)

View Rules

# Show routing policy
ip rule
ip rule show

# Default output:
# 0:      from all lookup local
# 32766:  from all lookup main
# 32767:  from all lookup default

Create Policy Routes

# Route specific source through different table
sudo ip rule add from 192.168.1.100 table 100
sudo ip route add default via 10.0.0.1 table 100

# Route by destination
sudo ip rule add to 10.0.0.0/8 table 100

# Route by fwmark (firewall mark)
sudo ip rule add fwmark 1 table 100

# Route by interface
sudo ip rule add iif eth0 table 100
sudo ip rule add oif eth0 table 100

# Set priority
sudo ip rule add from 192.168.1.100 table 100 priority 100

# Delete rule
sudo ip rule del from 192.168.1.100 table 100

ip netns (Network Namespaces)

Manage Namespaces

# List namespaces
ip netns list

# Create namespace
sudo ip netns add test-ns

# Delete namespace
sudo ip netns del test-ns

# Execute command in namespace
sudo ip netns exec test-ns ip addr
sudo ip netns exec test-ns bash

# Move interface to namespace
sudo ip link set eth1 netns test-ns

# Create veth pair for namespace connectivity
sudo ip link add veth0 type veth peer name veth1
sudo ip link set veth1 netns test-ns
sudo ip addr add 10.0.0.1/24 dev veth0
sudo ip link set veth0 up
sudo ip netns exec test-ns ip addr add 10.0.0.2/24 dev veth1
sudo ip netns exec test-ns ip link set veth1 up
sudo ip netns exec test-ns ip link set lo up

Monitor Namespace

# Monitor events in namespace
sudo ip netns exec test-ns ip monitor

# Identify namespace from PID
sudo ls -la /proc/<PID>/ns/net

ip monitor (Event Monitoring)

# Monitor all network events
ip monitor

# Monitor specific events
ip monitor link      # Interface changes
ip monitor addr      # Address changes
ip monitor route     # Routing changes
ip monitor neigh     # ARP changes

# Multiple event types
ip monitor link addr route

# With timestamps
ip -ts monitor

Troubleshooting Workflows

Check Network Connectivity

# 1. Check interface status
ip -br link

# 2. Check IP addresses
ip -br addr

# 3. Check default route
ip route | grep default

# 4. Check route to destination
ip route get 8.8.8.8

# 5. Check established connections
ss -tan state established

# 6. Check DNS connectivity
ss -tan 'dport = :53'

Debug Service Not Accessible

# 1. Is service listening?
ss -tulnp | grep :80

# 2. On correct interface?
ss -tulnp | grep :80 | grep -E '0\.0\.0\.0|::|\*'

# 3. Firewall blocking?
# (Check with firewalld/nftables)

# 4. Check connections to service
ss -tan 'dport = :80'

Diagnose Slow Network

# 1. Check interface errors
ip -s link show eth0 | grep -E 'errors|dropped'

# 2. Check for connection issues
ss -tan state time-wait | wc -l   # Too many = connection churn
ss -tan state close-wait | wc -l  # Leaking connections

# 3. Check buffer usage
ss -tmi | grep -E 'rcv_space|snd_wnd'

# 4. Check route metrics
ip route | grep metric

Network Namespace Debugging

# 1. Identify container's namespace
PID=$(docker inspect -f '{{.State.Pid}}' container_name)
sudo nsenter -t $PID -n ip addr

# 2. Or use ip netns
sudo ln -s /proc/$PID/ns/net /var/run/netns/container_ns
ip netns exec container_ns ip addr

Quick Command Reference

ss Quick Reference

ss -tulnp                          # Listening ports with process
ss -tan state established          # Established connections
ss -tan 'dport = :443'            # Connections to port 443
ss -tan 'dst 10.0.0.0/8'          # Connections to 10.x.x.x
ss -s                              # Statistics summary
ss -tan state time-wait | wc -l    # Count TIME_WAIT

ip Quick Reference

# Addresses
ip -br addr                        # Brief address list
ip addr add 192.168.1.100/24 dev eth0  # Add address
ip addr del 192.168.1.100/24 dev eth0  # Remove address

# Interfaces
ip -br link                        # Brief interface list
ip link set eth0 up/down           # Enable/disable
ip -s link show eth0               # Statistics

# Routes
ip route                           # Show routes
ip route get 8.8.8.8               # Route to destination
ip route add 10.0.0.0/8 via 192.168.1.1  # Add route
ip route del 10.0.0.0/8            # Delete route

# Neighbors
ip neigh                           # Show ARP table
ip neigh flush dev eth0            # Clear ARP cache

See Also