TCP — caratteristiche e struttura del segmento
Dal perché HTTP, SSH e FTP usano TCP, alle sei garanzie fondamentali, fino a header, flag, sequence number e opzioni moderne (MSS, Window Scale, SACK, Timestamps).
1. TCP — il protocollo che garantisce tutto
HTTP, HTTPS, SSH, FTP, SMTP: tutti usano TCP. Non è un caso. TCP è il protocollo di trasporto che garantisce che i dati arrivino a destinazione integri, ordinati e senza duplicati, indipendentemente da quello che succede nella rete sottostante. È la fondamenta su cui è costruita la maggior parte di Internet.
Ma questa garanzia ha un costo: TCP è complesso, ha un header minimo di 20 byte, richiede una connessione esplicita e mantiene stato su entrambi gli host. Capire come funziona internamente ti permette di capire perché alcune applicazioni sono lente, perché certi firewall si comportano in modo strano, e come i moderni protocolli come QUIC cercano di migliorarlo.
TCP è un protocollo di livello Transport connection-oriented, affidabile, full-duplex e byte-stream, con controllo di flusso (rwnd) e controllo di congestione (cwnd).
Le sei caratteristiche fondamentali
Handshake a tre vie
Prima di trasferire dati, TCP stabilisce una connessione con three-way handshake. Solo dopo che entrambi gli host hanno concordato parametri e ISN inizia il trasferimento.
ACK, ritrasmissione, riordino
Garanzia che ogni byte venga ricevuto correttamente tramite acknowledgment, ritrasmissione in caso di perdita e riordinamento di segmenti fuori sequenza.
Dati in entrambe le direzioni
Dati scorrono in entrambe le direzioni simultaneamente. Ogni lato ha Sequence Number indipendente. ACK e dati viaggiano con piggybacking.
Nessun confine di messaggio
TCP non conosce i confini dei messaggi applicativi. L'app invia un flusso continuo; TCP lo segmenta. Contrasto con UDP che è message-oriented.
Evita buffer overflow
Il ricevitore comunica spazio disponibile tramite Window Size. Il mittente non può inviare più byte di quanti il ricevitore possa accettare.
Evita collasso di rete
TCP adatta la velocità allo stato della rete tramite Slow Start, AIMD, CUBIC, BBR. Nessuna app può inviare a piena velocità se la rete è congestionata.
2. La struttura dell'header TCP
L'header TCP ha una dimensione minima di 20 byte (5 parole da 32 bit), espandibile fino a 60 byte con le opzioni. Ogni campo ha un ruolo preciso nel meccanismo di consegna affidabile.
Campi dell'header — analisi dettagliata
| Campo | Dimensione | Ruolo |
|---|---|---|
| Source Port | 16 bit | Porta del processo mittente (client: porta effimera; server: porta well-known) |
| Destination Port | 16 bit | Porta del processo destinatario — usata per il demultiplexing |
| Sequence Number | 32 bit | Numero del primo byte del payload in questo segmento. Inizializzato con l'ISN |
| Acknowledgment Number | 32 bit | Prossimo byte atteso dal ricevitore (ACK cumulativo). Valido solo se ACK=1 |
| Data Offset | 4 bit | Lunghezza header in parole da 32 bit. Min 5 (=20 byte), max 15 (=60 byte) |
| Reserved | 3 bit | Riservati, devono essere 0 |
| Flags | 9 bit | CWR, ECE, URG, ACK, PSH, RST, SYN, FIN — controllano la connessione |
| Window Size | 16 bit | Spazio disponibile nel buffer rx (byte). Base del controllo del flusso |
| Checksum | 16 bit | Pseudo-header IP + header TCP + dati. Obbligatorio (a differenza di UDP) |
| Urgent Pointer | 16 bit | Offset fino ai dati urgenti. Valido solo se URG=1, usato raramente |
| Options | 0–40 byte | Estensioni negoziabili: MSS, Window Scale, SACK, Timestamps |
3. I flag TCP — il linguaggio della connessione
I 9 bit di flag sono lo strumento con cui TCP comunica lo stato della connessione. Ogni flag attivo (=1) ha un significato preciso:
SYN
Synchronize — apertura connessione. Presente nel 1° e 2° messaggio del three-way handshake. Consuma 1 numero di sequenza.
ACK
Acknowledgment — il campo Ack Number è valido. Presente in quasi tutti i segmenti tranne il primo SYN.
FIN
Finish — chiusura graziosa. Chi invia FIN non trasmetterà più dati ma può ancora ricevere. Consuma 1 seq.
RST
Reset — chiusura immediata anomala. Nessun graceful close. Usato per stato inconsistente o rifiuto connessione.
PSH
Push — richiede al ricevitore di consegnare i dati all'app immediatamente senza aspettare il riempimento del buffer.
URG / CWR / ECE
URG = dati urgenti. CWR/ECE = Explicit Congestion Notification (RFC 3168). Raramente usati nelle implementazioni comuni.
Confondere FIN e RST: FIN è una chiusura ordinata (half-close possibile), RST è una chiusura brusca che scarta buffer e notifica errore all'app. In Wireshark, RST spesso indica porte chiuse o firewall che blocca.
All'interrogazione: SYN e FIN consumano 1 byte di sequenza anche se non trasportano payload. È una domanda trabocchetto classica! Ricorda: ISN casuale per sicurezza anti-hijacking.
4. Sequence Number, ACK cumulativo e Window Size
Sequence Number = numero del primo byte del payload nel flusso complessivo. Ack Number = prossimo byte atteso (ACK cumulativo che conferma tutto fino a N-1).
I campi Sequence Number e Acknowledgment Number sono il meccanismo centrale di TCP.
ISN pseudocasuale scelto all'apertura (non 0) per sicurezza anti IP spoofing e session hijacking. SYN e FIN = +1 seq. ACK cumulativo semplifica la gestione ma rende inefficienti perdite multiple senza SACK.
Window Size — il controllo del flusso in un campo
Il campo Window Size (16 bit) comunica al mittente quanti byte il ricevitore può ancora accettare nel suo buffer. Regola fondamentale:
Max 65535 byte. Con RTT=100ms e banda 1 Gbps, BDP ≈12,5 MB. Con window 64 KB il mittente aspetta ACK ogni 64 KB, sprecando banda. Soluzione: Window Scale (RFC 7323) moltiplicatore fino a 2¹⁴ = 16384× → window effettiva ~1 GB.
5. Opzioni TCP ed evoluzione da RFC 793 a RFC 9293
Le opzioni TCP estendono l'header base aggiungendo funzionalità negoziabili nell'handshake:
| Opzione | RFC | Funzione |
|---|---|---|
| MSS (Maximum Segment Size) | RFC 793 | Max payload che il mittente è disposto a ricevere. Negoziato in SYN. Evita frammentazione IP. Default 536, tipico 1460 su Ethernet (1500-20-20). |
| Window Scale | RFC 7323 | Moltiplicatore Window Size. Finisce ~1 GB su reti high BDP. |
| SACK Selective Acknowledgment | RFC 2018 | Segnala blocchi non contigui ricevuti. Ritrasmette solo mancanti, non tutto dal gap. |
| Timestamps | RFC 7323 | RTT preciso e PAWS — Protection Against Wrapped Sequences su connessioni velocissime. |
Il checksum TCP è calcolato su uno pseudo-header che include IP sorgente, destinazione, protocollo e lunghezza segmento — campi del livello IP. Viola la separazione dei livelli ma rileva errori di consegna ad indirizzi errati. Stessa tecnica usata da UDP.
Da RFC 793 (1981) a RFC 9293 (2022)
TCP è stato definito nel 1981 con RFC 793. Nel 2022 è stato aggiornato da RFC 9293 che consolida decenni di correzioni e best practice. RFC 793 è obsoleto. Le implementazioni moderne (Linux, Windows, BSD) seguono RFC 9293 + RFC aggiuntivi per SACK, CUBIC, BBR, TFO (TCP Fast Open) e altri.
RFC 793 → RFC 9293
Consolidamento, chiarimenti su ISN casuale, handling di opzioni, sicurezza. Documento di riferimento moderno.
CUBIC, BBR, TFO, SACK
Linux usa CUBIC/BBR, Window Scale automatico, SACK abilitato di default. Performance su high-bandwidth.
6. Verifica / Esercizio pratico
🔬 Attività — Analizza un flusso TCP
Usa Wireshark o tcpdump su una connessione HTTP verso un sito. Rispondi:
- Qual è il valore di MSS negoziato nel SYN? Corrisponde a 1460? Perché?
- Verifica Sequence Number: SYN e FIN consumano sequenza? Controlla Ack Numbers.
- Cerca Window Scale e SACK nel SYN: quali fattori di scala vedi? La connessione è SACK-permitted?
- Calcola BDP: bandwidth × RTT del percorso. La Window Size basta senza scaling?
1. 1460 = MTU 1500 Ethernet - 20 IP - 20 TCP. Se PPPoE → 1452. 2. Sì: Wireshark mostra Seq 0 per SYN ma next Seq =1. Stesso per FIN. 3. Window Scale tipico 7-8 su Linux (×128/256), SACK-Permitted=1 quasi sempre ON. 4. BDP alto su 1Gbps/100ms = 12,5 MB → serve WS, altrimenti throughput limitato a ~5 Mbps con 64KB.
7. Riepilogo e concetti chiave
📚 Prossimo passo — TCP handshake a tre vie e chiusura
Ora che conosci header e flag, vediamo come si apre e chiude davvero una connessione: SYN, SYN-ACK, ACK, FIN e stati TIME_WAIT, CLOSE_WAIT, con tcpdump in tempo reale.