Vai al contenuto
New

DeepSeek V4.1 Flash free for 7 days: 10M tokens a day after a top-up of $10 or more. Until Nov 30.

How it works

TCP/IP e porte: come i servizi restano in ascolto sulla tua macchina

Una porta è un ingresso numerato della tua macchina. Come TCP e UDP usano le porte e come avviare, trovare e testare un server locale su 127.0.0.1.

Base12 min di letturaDi NotHoly

Una porta è un numero che dice al sistema operativo quale programma deve ricevere una parte del traffico di rete. La tua macchina ha un indirizzo IP e può far girare decine di programmi di rete contemporaneamente: un browser che scarica pagine, un client di posta, un database, un web server locale. L'indirizzo IP porta il traffico al computer giusto. La porta lo consegna al programma giusto.

Se hai letto cosa fa il DNS, sai già come un nome diventa un indirizzo. Questo articolo spiega da dove vengono le porte, come le usano i due principali protocolli di trasporto e come vedere su quali porte è in ascolto la tua macchina. Il laboratorio gira su 127.0.0.1, l'indirizzo di loopback che significa sempre "questa macchina", quindi nulla esce dal tuo computer.

Che cos'è una porta

Una porta è un numero a 16 bit, quindi va da 0 a 65535. Gli header TCP e UDP contengono entrambi una porta di origine e una porta di destinazione. Quando un pacchetto raggiunge il tuo computer, il sistema operativo legge la porta di destinazione e consegna i dati al programma che ha chiesto di ricevere su quel numero.

Pensa a un condominio. L'indirizzo stradale fa arrivare la consegna al palazzo. Il numero dell'interno dice al corriere a quale porta bussare. In questa immagine l'indirizzo IP è il palazzo e la porta è l'interno. Qualcuno decide quale interno è quale, e un inquilino può andarsene e lasciare il numero a un altro.

Una porta in ascolto è una porta per cui un programma ha detto al sistema operativo, in sostanza, "manda a me le connessioni per questo numero". Un programma in questo stato è in ascolto. Quando il programma termina, il sistema operativo libera la porta e lì non risponde più nessuno.

Perché è importante

Ogni servizio che esegui apre almeno una porta. Questo vale anche per programmi che non hai avviato di proposito: strumenti di aggiornamento, client di sincronizzazione, server di sviluppo, plugin e software che si installa come servizio in background. L'elenco delle porte in ascolto è il modo più semplice di vedere con precisione cosa offre la tua macchina alla rete.

Se controlli un host tuo, quell'elenco è la prima cosa da annotare. Prima di chiederti se un servizio ha le patch o è configurato bene, devi sapere che esiste. Il lavoro di sicurezza comincia dall'inventario, e l'inventario comincia dalle porte.

I livelli in breve

TCP/IP è la suite di protocolli su cui gira internet. È organizzata in livelli, e per ora non ti servono tutti. Qui contano quattro livelli:

  • Collegamento: sposta i frame su un singolo segmento di rete locale, come Wi-Fi o Ethernet.
  • Internet: IP sposta i pacchetti tra host attraverso le reti, usando gli indirizzi IP.
  • Trasporto: TCP o UDP trasportano i dati tra programmi, usando le porte.
  • Applicazione: il protocollo che parla il programma, come HTTP, DNS o SSH.

Ogni livello avvolge i dati del livello superiore nel proprio header. L'header IP contiene gli indirizzi di origine e destinazione. L'header TCP o UDP contiene le porte di origine e destinazione. I dati dell'applicazione stanno all'interno. Quando il pacchetto arriva, ogni livello toglie il proprio header e passa il resto verso l'alto.

La porta sta nel livello di trasporto. IP non sa quale programma deve ricevere i dati. Quel compito spetta al livello di trasporto, ed è per questo che un solo indirizzo IP può servire una pagina web sulla porta 443 e un database sulla porta 5432 nello stesso momento.

Come TCP apre una connessione

TCP, specificato nella RFC 9293, dà a un programma un flusso di byte affidabile e ordinato. Prima che si muovano dati dell'applicazione, le due parti si accordano sui numeri di sequenza iniziali e confermano che ciascuna può inviare e ricevere. Questo accordo è il three-way handshake.

  1. Il client invia un segmento SYN. In parole semplici dice: voglio collegarmi alla porta 8000, e il mio numero di sequenza iniziale è X.
  2. Se un programma è in ascolto sulla porta 8000, il server risponde con un SYN-ACK. Conferma X e invia il proprio numero iniziale.
  3. Il client risponde con un ACK. Ora la connessione è aperta e il client può inviare la sua richiesta.

Quando nessun programma è in ascolto sulla porta, la macchina di destinazione non invia un SYN-ACK. Invia un segmento RST (reset), e il client rinuncia subito con un messaggio come "connection refused". Questa risposta rapida è utile. Ti dice che l'host ha ricevuto il pacchetto e che nessuno accetta connessioni su quella porta.

Un'attesa silenziosa che finisce in timeout significa altro. Molto spesso un firewall ha scartato i pacchetti senza rispondere. Quindi "refused" e "timed out" sono due indizi diversi. Impara a leggerli.

Le connessioni su 127.0.0.1 seguono la stessa logica TCP anche se i pacchetti non arrivano mai a una scheda di rete. Il sistema operativo esegue l'handshake via software, e questo rende l'indirizzo di loopback un posto sicuro per esercitarsi.

In cosa UDP è diverso

UDP, specificato nella RFC 768, è molto più semplice. Il suo header ha 8 byte: porta di origine, porta di destinazione, lunghezza e checksum. Non ci sono handshake, conferme, ritrasmissioni né ordinamento. Il mittente trasmette un datagramma, e la rete lo consegna oppure no. Il destinatario non conferma nulla, a meno che l'applicazione non implementi da sé questa logica.

Questa semplicità ha i suoi usi. Le query DNS viaggiano di solito su UDP, porta 53, perché una domanda breve e una risposta breve stanno in un solo scambio, e un handshake aggiungerebbe viaggi di andata e ritorno. Voce e video in tempo reale usano spesso UDP, e lo stesso fa QUIC, il trasporto sotto HTTP/3. Ognuno di questi protocolli ha le proprie regole per perdite e ritrasmissioni.

Per UDP le porte funzionano allo stesso modo. La porta di destinazione sceglie il programma. La differenza è che una porta UDP non ha stato di connessione. Qualsiasi programma associato a quella porta riceve tutto ciò che arriva, da chiunque lo invii. Un listener TCP vede solo le connessioni che completano l'handshake. Entrambi rispondono comunque alla stessa domanda: quale programma riceve questo pacchetto.

Chi decide cosa significa ogni numero

La Internet Assigned Numbers Authority (IANA) gestisce il Service Name and Transport Protocol Port Number Registry. Il registro indica quale servizio è comunemente associato a ogni numero di porta per TCP, UDP e pochi altri protocolli di trasporto. Tra le voci più note ci sono 22 per ssh, 53 per domain (DNS), 80 per http e 443 per https.

La RFC 6335 divide lo spazio dei numeri in tre intervalli:

  • Da 0 a 1023: porte di sistema, dette anche well-known. Molti sistemi permettono solo ai processi privilegiati di associarsi a queste porte.
  • Da 1024 a 49151: porte utente, dove i produttori registrano molti servizi.
  • Da 49152 a 65535: porte dinamiche o private. I client le usano spesso come porte di origine temporanee.

Il registro riporta assegnazioni e convenzioni. Né TCP né UDP le impongono. Qualsiasi programma con i permessi necessari può associarsi a quasi ogni porta libera. Il registro ti dice cosa gira di solito su un numero, e sulla tua macchina può sbagliare. Guarda cosa è davvero in ascolto prima di trarre una conclusione.

Laboratorio pratico: un web server locale su 127.0.0.1

Ti servono un terminale e Python 3. Il laboratorio usa il server HTTP integrato in Python, quindi non devi installare altro.

Ho eseguito i comandi per Windows qui sotto su Windows 11 Pro con Git Bash, Python 3.12.10 e curl 8.12.1. Non ho eseguito i comandi per Linux e macOS su questa macchina, quindi il loro output non è riportato. Dove compare un blocco di output, viene dal comando mostrato sopra.

Una nota su Python: nella mia sessione Git Bash python3 non veniva trovato, mentre python lanciava Python 3.12. Se su Windows python3 non funziona, usa python. Il resto del comando non cambia.

Passo 1: crea una cartella con un file

Il server pubblica tutto quello che si trova nella cartella da cui lo avvii, quindi prima mettici qualcosa di piccolo.

bash
mkdir -p ~/port-lab && cd ~/port-lab
printf '<!doctype html><title>lab</title><h1>Port 8000 lab</h1>\n' > index.html

Su PowerShell, crea la stessa cartella e scrivi quelle due righe in index.html con un editor qualsiasi.

Passo 2: avvia il server e lascialo in esecuzione

Tieni aperto questo terminale. Il server gira finché non lo fermi.

bash
cd ~/port-lab
python3 -m http.server 8000 --bind 127.0.0.1

Il flag --bind 127.0.0.1 dice a Python di ascoltare solo sull'interfaccia di loopback. Senza il flag, Python ascolta su ogni interfaccia della macchina. Questa differenza conterà più avanti, quando leggerai l'elenco delle porte in ascolto.

Passo 3: trova il socket in ascolto

Scegli il comando per il tuo sistema operativo. Ognuno elenca i socket in stato LISTEN che usano la porta 8000.

Linux:

bash
ss -tlnp | grep 8000

macOS:

bash
lsof -iTCP -sTCP:LISTEN -n -P | grep 8000

Windows PowerShell:

powershell
Get-NetTCPConnection -State Listen -LocalPort 8000

Questo è l'output che ho ottenuto dal comando Windows sulla mia macchina, passato attraverso Format-Table:

text
LocalAddress LocalPort  State OwningProcess
------------ ---------  ----- -------------
127.0.0.1         8000 Listen         45608

Sulla tua macchina l'ID di processo sarà diverso. Esegui Get-Process -Id <OwningProcess> con il tuo numero per confermare che il proprietario è il processo Python che hai avviato. Nella mia esecuzione era python.

Cosa controllare:

  • LocalAddress è 127.0.0.1. Il socket accetta connessioni solo da questa macchina. Se avessi omesso --bind, qui ti aspetteresti di vedere 0.0.0.0. Non ho testato questa variante sulla mia macchina, quindi prendilo come risultato atteso e non osservato.
  • State è Listen. Il socket è in attesa di connessioni.
  • OwningProcess indica il programma che ti aspetti. Se indica qualcosa che non riconosci, fermati e scopri di cosa si tratta prima di andare avanti.

Passo 4: collegati

Apri un secondo terminale ed esegui:

bash
curl -v http://127.0.0.1:8000/

Questo è l'output della mia esecuzione, ridotto alle righe che contano:

text
* Trying 127.0.0.1:8000...
* Connected to 127.0.0.1 (127.0.0.1) port 8000
> GET / HTTP/1.1
> Host: 127.0.0.1:8000
< HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.10
< Content-type: text/html
<!doctype html><title>lab</title><h1>Port 8000 lab</h1>

Leggilo in ordine. Trying significa che curl sta aprendo una connessione TCP. L'indirizzo è già un IP, quindi non avviene alcuna risoluzione DNS. Connected significa che il three-way handshake è terminato. GET / HTTP/1.1 è il livello applicazione: ora curl parla HTTP su quella connessione. 200 OK significa che il server ha trovato il file e ha risposto. La riga HTML in fondo è il tuo file.

Il server scrive una riga sulla richiesta nel proprio terminale. Il mio ha mostrato:

text
127.0.0.1 - - [08/Nov/2026 06:07:56] "GET / HTTP/1.1" 200 -

L'indirizzo di origine è lo stesso indirizzo di loopback, quindi la richiesta è partita da questa macchina.

Passo 5: ferma il server e riprova

Torna al terminale del server e premi Ctrl+C. È il modo pulito per fermarlo. Sulla mia macchina ho fermato il processo con Stop-Process -Force, che lo termina senza dargli modo di chiudersi in modo pulito. In entrambi i casi, il socket in ascolto sparisce quando il processo termina.

Conferma che il socket non c'è più:

powershell
Get-NetTCPConnection -State Listen -LocalPort 8000

Il mio output era vuoto. Poi esegui di nuovo lo stesso comando curl:

bash
curl -v http://127.0.0.1:8000/

Questo è l'output della mia esecuzione:

text
* Failed to connect to 127.0.0.1 port 8000 after 2048 ms: Could not connect to server
curl: (7) Failed to connect to 127.0.0.1 port 8000 after 2048 ms: Could not connect to server

Il codice di uscita di curl è stato 7, il codice che indica che non è riuscito a collegarsi.

È successo questo. Il tuo SYN ha raggiunto 127.0.0.1 sulla porta 8000. Lì non c'era nessuno in ascolto, quindi il sistema operativo ha risposto con un reset. curl ha segnalato subito il rifiuto, senza aspettare un timeout. Se invece vedi una lunga attesa seguita da un timeout, sospetta un firewall o una route che scarta i pacchetti.

Cosa mostra il laboratorio

Lo stesso indirizzo e la stessa porta si sono comportati in due modi. Con un listener, l'handshake è stato completato e il server ha risposto. Senza listener, il rifiuto è tornato in millisecondi. A separare i due casi è l'elenco delle porte in ascolto. Quando una connessione ti sorprende, controlla prima quell'elenco.

Errori comuni

Associarsi per sbaglio a tutte le interfacce. Molti server improvvisati ascoltano di default su tutti gli indirizzi. Su un portatile collegato alla rete di un bar, questo può esporre un server di sviluppo agli altri dispositivi sulla stessa rete. Usa un indirizzo di bind esplicito quando ti serve solo l'accesso locale.

Trattare il numero di porta come una prova d'identità. La porta 80 significa di solito HTTP, ma niente obbliga un programma a parlare HTTP lì. Collegati e leggi cosa invia il servizio, oppure controlla quale processo possiede il socket.

Dimenticare UDP. ss -tlnp mostra solo i listener TCP. Usa ss -ulnp per UDP, o Get-NetUDPEndpoint su Windows. Una macchina può avere un servizio UDP molto attivo che non compare mai nel tuo controllo TCP.

Leggere un timeout come "nessun servizio". Un timeout significa spesso che tra te e la porta c'è un filtro. Un rifiuto significa che l'host ha risposto e nessuno è in ascolto. Richiedono passi successivi diversi.

Terminare il processo sbagliato. Conferma il nome del processo proprietario e la sua riga di comando prima di fermarlo. Un server rimasto da un tentativo precedente può ancora occupare la porta e rispondere con i file di una cartella che non volevi pubblicare. Controlla il proprietario prima di dare per scontato che la porta sia tua.

Perché nel lavoro di sicurezza si comincia da qui

Le porte in ascolto descrivono cosa la tua macchina offre alla sua rete, che tu lo volessi o no. Prima di testare qualsiasi altra cosa su un host tuo, elenca cosa è in ascolto, associa ogni voce a un programma che conosci e chiudi quello che non ti serve. Un server di sviluppo che hai dimenticato di fermare è un buon esempio di voce che sembra innocua e continua a rispondere.

Gli stessi comandi si possono usare su macchine che non controlli, ma scansionare o sondare un sistema che non è tuo richiede il permesso scritto del proprietario. Esercitati solo sulle tue macchine e nel tuo laboratorio.

Come andare oltre

Ripeti l'esercizio con UDP. Nella mia esecuzione un breve listener Python su 127.0.0.1, porta 5399, ha ricevuto un datagramma da un mittente. Il listener non faceva nulla di speciale:

python
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("127.0.0.1", 5399))
data, addr = s.recvfrom(1024)
print("got", data, "from", addr)

Eseguilo in un terminale, poi invia un datagramma da un altro con socket.sendto. L'output che ho ottenuto è stato got b'hello' from ('127.0.0.1', 63411). Nota che non c'è stato alcun handshake. Il pacchetto è arrivato e basta. Sulla mia macchina la porta 5353 era già in uso e il bind è fallito con un errore di permessi, quindi per il test ho scelto la 5399.

Poi leggi la parte sull'instaurazione della connessione nella RFC 9293 e confrontala con il flusso di pacchetti descritto sopra. Dopo passa a come funziona HTTP, che spiega come HTTP gira sopra TCP e cosa contengono una richiesta e una risposta.

Fonti

RFC 9293, Transmission Control Protocol (TCP), IETF, agosto 2022. https://www.rfc-editor.org/rfc/rfc9293

RFC 768, User Datagram Protocol, IETF, agosto 1980. https://www.rfc-editor.org/rfc/rfc768

Service Name and Transport Protocol Port Number Registry, IANA. https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml

RFC 6335, Internet Assigned Numbers Authority (IANA) Procedures for the Management of the Service Name and Transport Protocol Port Number Registry, IETF, agosto 2011. https://www.rfc-editor.org/rfc/rfc6335

Fonti

  1. RFC 9293: Transmission Control Protocol (TCP)
  2. RFC 768: User Datagram Protocol
  3. IANA: Service Name and Transport Protocol Port Number Registry
  4. RFC 6335: IANA Procedures for the Service Name and Port Number Registry

Altro su Reti e web

Reti e web

Che cos'è TLS? Come HTTPS protegge il traffico

TLS 1.3 dà a HTTPS riservatezza, integrità e autenticazione del server. Impara l'handshake, le catene di certificati e ciò che il lucchetto non dimostra.

Base12 min di lettura