Il server web è davvero in ascolto sulla porta 443? Quale programma sta occupando la porta 8080? Quante connessioni ha aperte il mio computer, e verso chi? Sono domande di tutti i giorni per chi gestisce un server, e ss risponde a tutte.
Cos'è
ss (socket statistics) è lo strumento che mostra i socket del sistema, cioè i punti di comunicazione di rete usati dai programmi. Fa parte del pacchetto iproute2, lo stesso di ip, e ha sostituito netstat, che è obsoleto e spesso non è più installato. È più veloce, mostra più informazioni e ha una sintassi quasi identica per le opzioni più usate. Prima di cominciare, due parole:
- un programma in ascolto (listening) aspetta connessioni su una porta, come un server web sulla 80 e sulla 443;
- una connessione stabilita (established) è invece un collegamento già aperto tra due indirizzi, ciascuno composto da indirizzo IP e porta, per esempio
192.168.1.25:51234verso203.0.113.10:443.
Cosa fa
Elenca le connessioni e le porte in ascolto, con i protocolli (TCP, UDP, socket Unix), gli indirizzi, lo stato di ogni connessione e, se richiesto, il programma che le possiede. Senza opzioni mostra solo le connessioni stabilite, e quasi sempre le opzioni si scrivono unite in un'unica parola, come in ss -tulpn.
Come si usa
$ ss [opzioni] [filtro]Gli indirizzi negli esempi sono di documentazione o di reti private (192.168.1.x, 203.0.113.x), e i processi sono d'esempio.
Esempio 1: le porte in ascolto, il comando più usato
$ sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=13))
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=925,fd=6))
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=801,fd=3))
tcp LISTEN 0 80 127.0.0.1:3306 0.0.0.0:* users:(("mariadbd",pid=1034,fd=24))
tcp LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=925,fd=7))
tcp LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=801,fd=4))Le cinque lettere significano: -t TCP, -u UDP, -l solo quelli in ascolto (listening), -p mostra il processo e -n numeri al posto dei nomi (porte come 80 e non http, e nessuna risoluzione DNS, quindi più veloce). Senza sudo i processi degli altri utenti non vengono mostrati. Come leggere le colonne:
Netid: il protocollo (tcp,udp);State:LISTENper TCP in ascolto,UNCONNper UDP (che non ha connessioni);Local Address:Port: dove il programma è in ascolto;Peer Address:Port: l'altra parte (per i socket in ascolto è0.0.0.0:*, cioè "chiunque");Process: il programma, con il suo PID.
Esempio 2: l'indirizzo di ascolto cambia tutto
0.0.0.0:80 nginx visibile da tutte le interfacce, IPv4
[::]:80 lo stesso, in IPv6
127.0.0.1:3306 MariaDB visibile solo dal computer stesso
192.168.1.25:8080 in ascolto solo su quell'indirizzo specificoIl campo più importante per la sicurezza è l'indirizzo locale. 0.0.0.0 (o [::] per IPv6, o *) significa "in ascolto su tutte le interfacce": il servizio è raggiungibile dalla rete, se un firewall non lo impedisce. 127.0.0.1 (o [::1]) significa "solo da questo computer": ideale per un database o per un servizio dietro un reverse proxy come nginx, ma da fuori sono irraggiungibili. In pratica, quando un servizio "non risponde da fuori", la prima cosa da controllare è se è in ascolto su 0.0.0.0 o solo su 127.0.0.1.
Esempio 3: chi sta usando una porta?
$ sudo ss -ltnp 'sport = :8080'
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=4410,fd=5))
$ sudo ss -ltnp | grep ':5678'
LISTEN 0 4096 0.0.0.0:5678 0.0.0.0:* users:(("docker-proxy",pid=2211,fd=4))Quando un programma non parte perché "Address already in use", la porta è già occupata da qualcun altro. Si può filtrare per porta con 'sport = :8080' (source port, cioè la porta locale), oppure usare grep sull'output. Il campo Process dice di quale programma si tratta (con il PID, con cui si può controllare il processo con ps e fermarlo con kill). I servizi in Docker compaiono spesso come docker-proxy.
Esempio 4: le connessioni stabilite
$ ss -tn
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 0 192.168.1.25:51234 203.0.113.10:443
ESTAB 0 0 192.168.1.25:22 192.168.1.40:60112
ESTAB 0 0 192.168.1.25:38840 198.51.100.7:993
$ ss -tnp state established
$ ss -tn state established '( dport = :443 )'Senza -l, ss mostra le connessioni già aperte. ESTAB significa stabilita: ogni riga è una conversazione in corso tra due indirizzi. Nel primo esempio il computer è collegato a un sito in HTTPS (porta 443); nel secondo qualcuno (192.168.1.40) è collegato in SSH al tuo computer; nel terzo il computer controlla la posta (porta 993). Il filtro state established limita l'elenco, e dport (destination port) filtra per porta di destinazione.
Esempio 5: contare le connessioni per stato
$ ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -nr
214 ESTAB
37 TIME-WAIT
4 LISTEN
1 CLOSE-WAIT
$ ss -s
Total: 412
TCP: 255 (estab 214, closed 40, orphaned 0, timewait 37)
Transport Total IP IPv6
TCP 215 200 15
UDP 12 9 3Con -a (all) si vedono tutti i socket, in ogni stato. Combinando awk, sort e uniq -c si ottiene un conteggio per stato, utile per capire se un server ha troppe connessioni aperte. ss -s offre direttamente un riepilogo statistico. Gli stati più comuni: ESTAB (aperta), TIME-WAIT (chiusa da poco, in attesa di sicurezza), CLOSE-WAIT (l'altro lato ha chiuso, ma il programma locale no: se se ne accumulano tanti, è di solito un difetto del programma) e SYN-RECV (connessione in avvio: un numero molto alto può indicare un attacco o un sovraccarico).
Esempio 6: chi si collega al mio server?
$ ss -tn state established '( sport = :443 )' | awk 'NR>1 {print $4}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -n 5
38 198.51.100.23
12 203.0.113.77
9 192.0.2.45
4 198.51.100.9
2 203.0.113.5Un uso tipico su un server web: le connessioni stabilite sulla porta 443 (sport = :443, la porta locale), con l'indirizzo del cliente estratto dalla quarta colonna (Peer Address:Port), contate per indirizzo e ordinate. Si individuano subito i client più "pesanti" o un abuso. Funziona con IPv4; con IPv6 gli indirizzi contengono altri due punti, e il cut va adattato. Gli stessi strumenti sono quelli degli articoli su cut, sort e uniq.
Esempio 7: filtri per indirizzo e per porta
$ ss -tn dst 203.0.113.10
$ ss -tn dst 203.0.113.0/24
$ ss -tn dport = :22
$ ss -tn 'dport = :22 or dport = :443'
$ ss -tn src 192.168.1.25 sport = :22Il filtro finale accetta src / dst (indirizzo sorgente e destinazione, anche con rete e maschera), sport / dport (porta sorgente e destinazione), con operatori come =, !=, >, < e le parole and / or. Se il filtro ha parentesi, spazi o simboli di confronto, va scritto tra apici perché non lo interpreti la shell. Per ss "sorgente" significa sempre il lato locale e "destinazione" il lato remoto: sport = :443 sono le connessioni arrivate alla porta 443 di questo computer (un server), mentre dport = :443 sono quelle che questo computer ha aperto verso la porta 443 di altri (un client).
Esempio 8: i dettagli di una connessione e i tempi
$ ss -tnpo state established '( dport = :443 )'
Recv-Q Send-Q Local Address:Port Peer Address:Port Process
0 0 192.168.1.25:51234 203.0.113.10:443 users:(("firefox",pid=3210,fd=92)) timer:(keepalive,119min,0)
$ ss -tni dst 203.0.113.10
ESTAB 0 0 192.168.1.25:51234 203.0.113.10:443
cubic wscale:7,7 rto:204 rtt:14.5/6.2 mss:1448 cwnd:10 bytes_sent:5120 bytes_received:48213 ...Con -o si vedono i temporizzatori (per esempio quando scade il keepalive), con -i le informazioni interne di TCP: tempo di andata e ritorno (rtt, in millisecondi), finestra di congestione (cwnd), byte inviati e ricevuti. Sono utili per diagnosticare connessioni lente o instabili, e vanno oltre l'uso quotidiano.
Esempio 9: i socket Unix e gli altri protocolli
$ ss -xl
Netid State Recv-Q Send-Q Local Address:Port
u_str LISTEN 0 4096 /run/mysqld/mysqld.sock 24571 * 0
u_str LISTEN 0 4096 /var/run/docker.sock 25881 * 0
$ ss -4 -tn
$ ss -6 -tn
$ ss -ltn6Oltre alla rete, ss mostra i socket Unix (-x): canali di comunicazione tra programmi sulla stessa macchina, che al posto di una porta usano un file (come /run/mysqld/mysqld.sock per il database o /var/run/docker.sock per Docker). Con -4 e -6 si limita l'elenco a IPv4 o a IPv6. Altre opzioni per i protocolli: -w per i socket grezzi (raw) e --packet per quelli a livello di pacchetto.
Esempio 10: seguire i cambiamenti nel tempo
$ watch -n 2 'ss -s'
$ watch -n 1 "ss -Htn state established '( sport = :443 )' | wc -l"ss mostra una fotografia dell'istante in cui lo si lancia. Per osservare l'evoluzione si usa watch, che ripete il comando a intervalli (qui ogni 2 secondi o ogni secondo) e mostra l'ultimo risultato a schermo; si esce con Ctrl+C. Nel secondo esempio -H toglie la riga d'intestazione e wc -l conta le connessioni: si vede in diretta quante ce ne sono.
Esempio 11: uso negli script
#!/bin/bash
PORTA="${1:?Indica la porta da controllare}"
if ss -ltn "sport = :$PORTA" | grep -q LISTEN; then
echo "Qualcuno è in ascolto sulla porta $PORTA"
else
echo "Nessun servizio in ascolto sulla porta $PORTA" >&2
exit 1
fiUno script così verifica che un servizio sia in ascolto prima di fare altro (per esempio dopo un riavvio con systemctl). Il filtro "sport = :$PORTA" è un unico argomento tra virgolette doppie, in modo che la shell sostituisca la variabile. grep -q non stampa nulla e restituisce solo un codice di uscita (0 se trova LISTEN), che if usa. Per controllare da fuori se una porta risponde, invece, ss non basta: si usa uno strumento come curl o nc da un altro computer, perché un firewall potrebbe bloccarla anche se il servizio è in ascolto.
Opzioni utili
-t/-u/-x: socket TCP / UDP / Unix;-4/-6: solo IPv4 / IPv6.-l: solo quelli in ascolto;-a: tutti, in ascolto e non; senza opzioni: solo le connessioni stabilite.-n: numeri invece dei nomi (più veloce, senza risoluzione DNS);-r: risolve i nomi.-p: mostra il processo (servesudoper quelli degli altri utenti).-s: riepilogo statistico;-o: temporizzatori;-i: informazioni interne TCP;-e: dettagli estesi (utente, inode).-H: nasconde la riga d'intestazione (comodo negli script);-O: una riga per socket.state STATO: filtra per stato (established,listening,time-wait,close-wait…);src,dst,sport,dport: filtri per indirizzo e porta.-K: chiude le connessioni corrispondenti al filtro (se il kernel lo permette; richiedesudo).
Attenzione a
- Servono
sudoe-pper conoscere il programma: senza privilegi, la colonnaProcessè vuota per i processi degli altri utenti, e questo è l'errore più comune quando "non si vede" il servizio. - Un servizio in ascolto non è raggiungibile da fuori:
ssdice cosa succede nel computer. Un firewall (ufw,nftables), il router o il fornitore della VPS possono comunque bloccare la porta. E se l'indirizzo di ascolto è127.0.0.1, da fuori il servizio non c'è. 0.0.0.0è diverso da127.0.0.1: un database in ascolto su0.0.0.0:3306è offerto a chiunque possa raggiungerlo. Salvo necessità reale, i servizi interni dovrebbero restare su127.0.0.1, o essere protetti da un firewall.- Senza
-nè più lento e meno chiaro:ssprova a trasformare gli indirizzi in nomi (e le porte in nomi di servizio, comehttpossh), e per alcuni indirizzi l'operazione richiede tempo. Salvo esigenze particolari, usa sempre-n. - Le opzioni si fondono, e l'ordine non conta:
-tulpn,-lntpe-pntlusono equivalenti. Senza-te-u(o-a) può darsi che non si veda ciò che si cerca. - I filtri vogliono gli apici: parentesi,
>,<e!hanno un significato per la shell. Scrivi'( sport = :443 )'tra apici, e lascia gli spazi intorno a=e alle parentesi. - Sono dati istantanei: le connessioni nascono e muoiono in millisecondi, quindi una sola esecuzione può non mostrare un problema intermittente. Per seguirlo nel tempo,
watcho un registro. - Docker cambia il quadro: le porte pubblicate da un container compaiono come
docker-proxy(o, in alcune configurazioni, non compaiono affatto, perché il traffico viene deviato dal firewall senza un processo in ascolto). Se un servizio in Docker "non c'è" inss, controlla condocker ps. - TIME-WAIT in gran numero è normale su un server molto frequentato;
CLOSE-WAITche cresce nel tempo no, perché indica un programma che non chiude le connessioni. - Non fidarti solo di
grep:ss -tln | grep 80trova anche8080,1800e:80sul lato remoto. Usa il filtro'sport = :80', oppure un modello preciso comegrep ':80 '. -Kchiude connessioni reali: consudo ss -K dst 203.0.113.10si interrompono tutte le connessioni verso quell'indirizzo, comprese quelle SSH con cui stai lavorando. Va usato con molta cautela (e funziona solo se il kernel è compilato con il supporto).- I vecchi comandi:
netstat -tulpncorrisponde ass -tulpn; chi conosce il primo trova le stesse opzioni.lsof -i :8080è un'altra alternativa, per sapere chi usa una porta.
Riepilogo
| Comando | Cosa fa |
|---|---|
sudo ss -tulpn | Porte TCP e UDP in ascolto, con i programmi |
sudo ss -ltnp 'sport = :8080' | Chi usa la porta 8080 |
ss -tn | Connessioni TCP stabilite |
ss -tnp state established | Connessioni stabilite, con il programma |
ss -tan | Tutti i socket TCP, in ogni stato |
ss -s | Riepilogo statistico |
ss -tn dst 203.0.113.10 | Connessioni verso un certo indirizzo |
ss -tn 'dport = :443' | Connessioni verso la porta 443 |
ss -tni | Informazioni interne di TCP (tempi, byte) |
ss -xl | Socket Unix in ascolto |
ss -4 / ss -6 | Solo IPv4 / solo IPv6 |
watch -n 2 'ss -s' | Segue le statistiche nel tempo |