- Prima di ogni richiesta HTTP il kernel fa un handshake in 3 pacchetti: SYN → SYN+ACK → ACK
- I flag TCP (
[S],[S.],[.],[P.],[R],[F]) si leggono tutti in tcpdump in tempo reale - RST = chiusura brusca (porta chiusa, firewall, crash) - molti RST consecutivi sono segnale sospetto
- I log applicativi non vedono un SYN scan - serve tcpdump a livello di rete
▶ $ history
Stai costruendo un'API. Il client manda una richiesta, il server risponde. Funziona. Ma cosa succede esattamente tra il momento in cui scrivi fetch("https://api.example.com/data") e quello in cui arriva la risposta?
Apri tcpdump e guarda:
sudo tcpdump -i any -n 'host api.example.com'192.168.1.10 > 93.184.216.34.443: Flags [S] # il tuo client
93.184.216.34.443 > 192.168.1.10: Flags [S.] # il server risponde
192.168.1.10 > 93.184.216.34.443: Flags [.] # connessione aperta
192.168.1.10 > 93.184.216.34.443: Flags [P.] # qui partono i dati
93.184.216.34.443 > 192.168.1.10: Flags [.] # server conferma ricezioneTre pacchetti prima che un singolo byte di payload si muova. Questo è il TCP handshake.

Come funziona#
TCP è un protocollo orientato alla connessione: prima di trasmettere dati, le due macchine negoziano. Questo garantisce che entrambi siano pronti e che i pacchetti arrivino nell'ordine corretto.
La negoziazione usa i flag TCP - bit nell'header del pacchetto che dichiarano l'intenzione di quel pacchetto:
| Flag | Simbolo tcpdump | Significato |
|---|---|---|
| SYN | [S] | Voglio aprire una connessione |
| SYN+ACK | [S.] | Ok, sono pronto - e tu? |
| ACK | [.] | Ho ricevuto il tuo pacchetto |
| PSH | [P.] | Manda i dati subito, non aspettare il buffer |
| RST | [R] | Chiusura brusca - porta chiusa, firewall, o errore |
| FIN | [F] | Ho finito di mandare - chiudiamo in modo ordinato |
Dal punto di vista del tuo codice, il handshake avviene dentro la syscall connect() - prima ancora che il tuo fetch() possa scrivere la prima riga HTTP.
Il three-way handshake#
Client Server
| |
| -------- [S] SYN -------> | "voglio connettermi"
| |
| <------- [S.] SYN+ACK ---- | "ok, sono pronto. e tu?"
| |
| -------- [.] ACK -------> | "confermato, partiamo"
| |
| CONNESSIONE APERTA |
| |
| -------- [P.] dati ------> | qui iniziano i dati veri
| |
| <------- [.] ACK ---------- | "ricevuto"Il terzo pacchetto [.] è solo ACK - lunghezza zero, nessun dato. I dati viaggiano solo dopo che la connessione è stabilita.
Chiudere una connessione: FIN vs RST#
Quando la comunicazione finisce ci sono due strade - e dal punto di vista della sicurezza sono molto diverse:
FIN - chiusura elegante:
Client Server
| -- [F.] --> | "ho finito di mandare"
| <-- [.] --- | "ricevuto"
| <-- [F.] -- | "anch'io ho finito"
| -- [.] ---> | "ok, ciao"
connessione chiusa correttamenteRST - chiusura brusca:
Server Client
| -- [R] ---> | connessione tagliata immediatamenteRST significa: porta chiusa, firewall che blocca, servizio che crasha, oppure qualcuno che sta facendo un port scan.
Molti FIN → traffico normale, sessioni che chiudono correttamente
Molti RST → segnale sospetto:
- port scan in corso
- servizio instabile che crasha
- firewall che blocca connessioni
- SYN flood in attoCosa vedi con tcpdump#
Filtra per host o porta per non annegare nell'output:
# Tutto il traffico verso un host specifico
sudo tcpdump -i any -n 'host api.example.com'
# Solo TCP, porta 443 (HTTPS)
sudo tcpdump -i any -n 'tcp and port 443'
# Solo i pacchetti SYN - chi si sta connettendo
sudo tcpdump -i any -n 'tcp[tcpflags] & tcp-syn != 0'Ogni riga corrisponde a un pacchetto. I flag sono dentro le parentesi quadre. L'ordine in cui appaiono è l'ordine reale in cui viaggiano sulla rete.
Il lato sicurezza: riconoscere un port scan#
Un nmap -sS (SYN scan) produce un pattern riconoscibile in tcpdump:
14:30:45.000 IP 10.0.0.50 > 10.0.0.3.22: Flags [S.] → porta aperta
14:30:45.001 IP 10.0.0.50 > 10.0.0.3.23: Flags [R.] → porta chiusa
14:30:45.001 IP 10.0.0.50 > 10.0.0.3.80: Flags [R.] → porta chiusa
14:30:45.002 IP 10.0.0.50 > 10.0.0.3.443: Flags [S.] → porta aperta
14:30:45.002 IP 10.0.0.50 > 10.0.0.3.3306: Flags [R.] → porta chiusaSegnali: stesso IP verso molte porte in rapida sequenza, mix di [S.] e [R.] come risposta, nessun [.] di completamento.
La cosa importante: auth.log e i log SSH sono vuoti - il SYN scan non completa mai il handshake, quindi il servizio non registra nulla. tcpdump a livello di rete vede tutto. I log applicativi da soli non bastano.
exit 0#
Il TCP handshake è il livello sotto il tuo codice - avviene prima che HTTP, TLS, o il tuo JSON si muovano di un millimetro. Capire i flag cambia come leggi gli errori di rete: un timeout è diverso da un RST, un FIN è diverso da un drop silenzioso.
La prossima volta che un'API non risponde, apri tcpdump. I flag raccontano esattamente cosa è successo.




