Soluzione 1:
Un ACK TCP di base dice "Ho ricevuto tutti i byte fino a X". L'ACK selettivo ti consente di dire "Ho ricevuto byte X-Y e V-Z".
Quindi, ad esempio, se un host ti ha inviato 10.000 byte e 3000-5000 byte sono stati persi durante il transito, ACK direbbe "Ho ricevuto tutto fino a 3000". L'altra estremità dovrebbe inviare nuovamente i byte 3001-10000. SACK potrebbe dire "Ho ricevuto 1000-2999 e 5001-10000" e l'host invierebbe solo 3000-5000.
Questo è ottimo su un collegamento con larghezza di banda elevata, perdita (o ritardo elevato). Il problema è che può causare gravi problemi di prestazioni in circostanze specifiche. I normali ACK TCP faranno in modo che il server tratti una connessione con perdita di larghezza di banda elevata con i guanti (invia 500 byte, attendi, invia 500 byte, attendi, ecc.). SACK gli consente di adattarsi all'elevato ritardo perché sa esattamente quanti pacchetti erano effettivamente perso.
Qui è dove possono accadere cose brutte. Un utente malintenzionato può costringere il tuo server a mantenere un'enorme coda di ritrasmissione per molto tempo, quindi elaborare l'intera dannata cosa ancora e ancora e ancora. Questo può bloccare la CPU, consumare RAM e consumare più larghezza di banda di quanto dovrebbe. In poche parole, un sistema leggero può avviare un DoS contro un server più robusto.
Se il tuo server è robusto e non serve file di grandi dimensioni, sei abbastanza ben isolato da questo.
Se servi principalmente una intranet o un altro gruppo di utenti a bassa latenza, SACK non ti compra nulla e può essere disattivato per motivi di sicurezza senza perdita di prestazioni.
Se sei su un collegamento a larghezza di banda ridotta (diciamo 1 Mbps o meno come regola empirica del tutto arbitraria), SACK può causare problemi nelle normali operazioni saturando la tua connessione e dovrebbe essere disattivato.
Alla fine, tocca a te. Considera cosa stai servendo, a chi, da cosa, e soppesa il grado del tuo rischio rispetto agli effetti sulla performance di SACK.
C'è un'ottima panoramica di SACK e della sua vulnerabilità qui.
Soluzione 2:
Un altro motivo per cui TCP SACK è spesso disabilitato è che esiste un'incredibile quantità di apparecchiature di rete là fuori che non riescono a gestire correttamente questa opzione. Lo vediamo sempre con un prodotto di trasferimento file ad alta velocità che forniamo che utilizza TCP. Il problema più comune è quello dei dispositivi gateway che eseguono operazioni come la randomizzazione dei numeri di sequenza per i pacchetti TCP che transitano attraverso il dispositivo dalle reti interne a quelle esterne, ma che non "annullano la casualità" delle opzioni TCP SACK che potrebbero essere inviate dal telecomando fine. Se i valori SACK effettivi non vengono ricondotti ai valori corretti da questi dispositivi, la sessione TCP non verrà mai completata a fronte della perdita di pacchetti quando l'estremità remota tenta di utilizzare SACK per ottenere i vantaggi dell'ACK selettivo.
Probabilmente questo sarebbe un problema minore se le persone applicassero in modo più aggressivo la manutenzione preventiva del software a questa attrezzatura, ma tendono a non farlo.
Soluzione 3:
Posso confermare per amara esperienza che tcp_sack =1 provoca il blocco del trasferimento dei dati su sftp/rsync/scp ecc. con file superiori a circa 12 MB quando si utilizzano determinate appliance firewall Cisco ASA.
OGNI volta sarebbe bloccato.
Stavamo effettuando il trasferimento su un collegamento dedicato a 100 Mbps tra l'host A e l'host B in due diversi data center, entrambi utilizzando il firewall Cisco e switch hardware con centos.
Questo può essere in qualche modo mitigato modificando le dimensioni del buffer, ad es. Non sono riuscito a trasferire un file da 1 GB tramite sftp dall'host A all'host B a meno che non imposti il buffer sftp su 2048, ma potrei fare a meno che l'host B stesse estraendo il file da A.
Gli esperimenti con lo stesso file utilizzando rsync e l'ottimizzazione del buffer di invio/ricezione mi hanno permesso di ottenere fino a circa 70 MB di un file da 1 GB trasferito da A a B.
Tuttavia, la risposta definitiva era disabilitare tcp_sack sull'host A. Inizialmente impostando tcp_sack =0 nel kernel al volo, ma alla fine l'ho aggiunto al mio /etc/sysctl.conf