L’accesso funziona, PWD funziona, e poi LIST si blocca finché il client non rinuncia o passa a un’altra modalità dati. Questa separazione è la firma: la connessione di controllo verso la porta 21 è sana, mentre la connessione dati viene costruita da un indirizzo o una porta che l’altro lato non riesce a raggiungere. Dietro un gateway VPN che fa anche NAT, il colpevole abituale è un comando FTP il cui payload nomina un indirizzo di tunnel come 10.8.0.6. La traduzione delle intestazioni non tocca mai quel valore.

Quello che segue è da dove viene quel valore, e quale scatola ha il permesso di cambiarlo.

Ciò che si rompe è il payload, non il tunnel

FTP mette l’endpoint dei dati dentro il flusso di controllo. In modalità attiva il client invia PORT con il proprio indirizzo e la propria porta, e il server richiama quella coppia. In modalità passiva il server risponde 227 con una coppia, e il client richiama quella al suo posto.

Entrambe le forme portano lo stesso tipo di affermazione: collegati a questo indirizzo, su questa porta. Un dispositivo che riscrive solo le intestazioni IP e TCP lascia l’affermazione intatta, così un lato continua a cercare di raggiungere un indirizzo che esiste solo dall’altra parte di un tunnel. La connessione dati si blocca dopo che la connessione di controllo è già stata dichiarata sana.

Tre modalità, tre payload

La tabella qui sotto mostra a quale lato viene chiesto di chiamare, e cosa può fare al riguardo un NAT che riscrive solo le intestazioni.

Leggete l’ultima colonna come la cosa che fallisce per prima. In modalità attiva è il server a chiamare un indirizzo privato; in modalità passiva è il client; con FTPS il payload è testo cifrato e la scatola intermedia ha ancora meno con cui lavorare.

ModeValue in the control streamWho dials whomHeader-only NAT leaves
Active (PORT)client address and portserver dials the clienta server dialing an unreachable tunnel address
Passive (227)server address and portclient dials the servera client dialing an address it cannot route to
FTPSthe same values, inside TLSas aboveciphertext, so no rewrite happens at all

Mettete l’helper dove avviene la traduzione

Su Linux la riscrittura del payload la fa l’helper nf_conntrack_ftp. Sorveglia la connessione di controllo, impara la porta negoziata, crea un’attesa per il flusso dati e, su una scatola NAT, riscrive l’indirizzo e la porta dentro il payload. Aiuta solo sul dispositivo che traduce l’indirizzo del client. Caricarlo sul client, o su un router che si limita a inoltrare il flusso, non cambia nulla della sessione.

Questi tre comandi mostrano se il modulo è presente, se è agganciato e se esiste un’attesa mentre una sessione è aperta:

modprobe nf_conntrack_ftp
lsmod | grep nf_conntrack_ftp
conntrack -L expect | grep ftp

Caricare il modulo non è la stessa cosa che agganciarlo. I kernel da 4.7 in poi arrivano con net.netfilter.nf_conntrack_helper=0, quindi l’helper attende una regola esplicita, per esempio iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp. Se la lista delle attese resta vuota mentre si tenta un trasferimento, è l’aggancio da controllare, non il modulo.

Modalità passiva: dite al server cosa annunciare

La modalità passiva è più facile da rendere deterministica perché si può dire al server cosa mettere nella risposta 227. In vsftpd è pasv_address, insieme a pasv_min_port e pasv_max_port; ProFTPD usa MasqueradeAddress e PassivePorts. Impostatele per prime, perché un indirizzo annunciato correttamente elimina la necessità di riscrivere qualsiasi cosa da quel lato.

Poi lasciate passare esattamente quell’intervallo di porte dal gateway, per esempio -A FORWARD -i tun0 -p tcp --dport 30000:30100 -j ACCEPT, così la regola corrisponde a ciò che il server annuncia.

Le due impostazioni devono concordare. Un server a cui si dice di annunciare 30000-30100 mentre il gateway consente 40000-40100 fallisce nel modo meno utile: la conversazione di controllo sembra sana e ogni connessione dati muore. Confrontate i numeri prima di fare debug su qualsiasi altra cosa.

Due firme di guasto, e cosa elimina FTPS

Un blocco su LIST indica la prima connessione dati della sessione, dove devono funzionare sia la riscrittura dell’indirizzo sia l’attesa. Un blocco su RETR dopo un LIST funzionante indica il trasferimento stesso, cioè l’intervallo passivo o l’MTU del tunnel. Questa seconda firma non è un problema di payload, e le impostazioni dell’helper non la risolveranno.

FTP su TLS elimina il payload che l’helper legge. Una scatola intermedia non può riscrivere un valore PORT o PASV che non riesce a decifrare, quindi restano un proxy che termina TLS, un server che annuncia un indirizzo raggiungibile entro un intervallo limitato, o un protocollo di trasferimento diverso.

Un breve ordine di controlli

Lavorate dal sintomo verso l’esterno. Confermate che LIST fallisce mentre PWD riesce, catturate l’indirizzo dentro il payload PORT o 227, e chiedete quale dispositivo traduce quell’indirizzo. Agganciate lì l’helper, osservate la lista delle attese durante un trasferimento, poi correggete la modalità passiva sul server e rispecchiate l’intervallo nella regola del gateway.

Tenete il guasto del percorso dati separato dal guasto del trasferimento massivo, perché portano a impostazioni diverse.

Articoli correlati