SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor

FTP passivo: perché il firewall blocca l'elenco file

Il login FTP riesce, ma l'elenco resta in attesa: configura un intervallo fisso di porte passive e autorizzalo nella regola del firewall.

Perché FTP accetta il login ma si blocca durante l'elenco delle directory

La modalità passiva di FTP non funziona attraverso un firewall perché FTP usa due connessioni TCP, non una sola. La connessione alla porta 21 trasporta il login e i comandi, quindi il nome utente e la password vengono accettati e il firewall sembra configurato correttamente. Il primo ls richiede quindi una seconda connessione su una porta diversa. Il firewall non consente questa connessione, quindi il client resta in attesa fino alla scadenza del timeout.

La soluzione consiste nel definire un intervallo fisso di porte per queste connessioni dati e nell'aggiungere una regola del firewall che consenta lo stesso intervallo. Un server dietro NAT (network address translation) richiede un'ulteriore impostazione per pubblicizzare l'indirizzo corretto. In passato gli helper per il connection tracking svolgevano automaticamente questa funzione. Oggi non lo fanno più. È importante capire il motivo prima di copiare una guida obsoleta.

Il canale di controllo e il canale dati

FTP (file transfer protocol) è definito nella RFC 959 ed è precedente sia al NAT sia al firewall stateful. Una sessione apre una connessione di controllo sulla porta TCP 21 e la mantiene attiva per tutta la sessione. I comandi vengono inviati in testo non cifrato. Le risposte sono costituite da un codice a tre cifre e da una riga di testo. Questa connessione non trasporta mai il contenuto dei file.

Ogni trasferimento di dati usa una connessione TCP distinta: una per un elenco di directory (LIST), una per ogni download (RETR) e una per ogni upload (STOR). La connessione viene aperta, usata una sola volta e chiusa. L'autenticazione avviene interamente sul canale di controllo, quindi un percorso dati non funzionante produce sempre lo stesso comportamento: accesso riuscito, quindi blocco. Se il client visualizza una risposta 230 e poi si blocca durante l'elenco, il problema riguarda il canale dati, non le credenziali.

Modalità attiva: il server si riconnette al client

In modalità attiva, il client sceglie una porta, resta in ascolto su quella porta e comunica al server la porta a cui connettersi:

PORT 192,168,1,50,195,80

I primi quattro numeri sono l'indirizzo IP del client. Gli ultimi due rappresentano la porta, codificata come due byte: 195 * 256 + 80 = 50000. Il server apre quindi la connessione dati dalla propria porta 20 verso la porta 50000 del client.

Dal punto di vista del client, questa connessione è in ingresso e non richiesta, quindi il firewall del client la blocca. Se il client si trova dietro un router domestico, l'indirizzo indicato nel comando PORT è un indirizzo privato che il server non può raggiungere. È in modalità attiva che FTP si è guadagnato la reputazione di protocollo che spesso non funziona.

Modalità passiva: il client apre entrambe le connessioni

La modalità passiva inverte la connessione dati. Il client invia PASV e il server risponde con un indirizzo e una propria porta:

227 Entering Passive Mode (203,0,113,10,195,80)

La codifica è la stessa, quindi il client si connette a 203.0.113.10 sulla porta 50000. Il client apre ora entrambe le connessioni. Per questo la modalità passiva funziona attraverso il NAT lato client e per questo tutti i client attuali la richiedono per prima.

Il problema si è spostato, non è scomparso. La connessione in ingresso non richiesta arriva ora al server, su una porta alta che cambia a ogni trasferimento. Quel firewall è sotto il tuo controllo, quindi ora il problema riguarda il tuo firewall.

EPSV (modalità passiva estesa, RFC 2428) segue lo stesso principio, ma usa una risposta più semplice:

229 Entering Extended Passive Mode (|||50000|)

La risposta non contiene alcun indirizzo. Il client riutilizza l'indirizzo già usato per la connessione di controllo. Questo permette il funzionamento su IPv6 ed elimina un'intera classe di problemi legati al NAT. Il manuale di curl indica che curl prova normalmente prima EPSV e poi PASV. La porta viene comunque scelta a runtime, quindi EPSV non modifica le regole del firewall.

Perché una normale regola del firewall non può consentire il canale dati

Il problema è che il numero di porta non esiste ancora quando si scrive la regola. Il server lo sceglie per ogni trasferimento. Con i valori predefiniti, vsftpd documenta pasv_min_port e pasv_max_port come 0, cioè «usa qualsiasi porta»: la connessione dati può quindi arrivare su qualsiasi porta superiore a 1023. sudo ufw allow 21/tcp consente il canale di controllo e nient’altro. È esattamente questa configurazione a produrre un login funzionante e un elenco delle directory che non viene caricato. Se il concetto di un servizio in ascolto su una porta fissa non è ancora chiaro, come funzionano le porte e i socket in ascolto su Linux fornisce il contesto necessario.

Un firewall stateful tiene traccia delle connessioni e il kernel può accettare una nuova connessione come RELATED a una connessione esistente. Per FTP, però, è necessario che un componente legga il flusso di controllo ed estragga la porta da una riga 227 o PORT. Per impostazione predefinita, non lo fa alcun componente.

Perché l'helper di tracciamento delle connessioni FTP non è più la soluzione

Il modulo del kernel nf_conntrack_ftp è quello indicato dalle guide meno recenti. Legge il canale di controllo in chiaro, individua la porta annunciata e registra un'aspettativa, quindi la connessione dati viene autorizzata senza alcuna regola che ne indichi la porta. Da quando sono state scritte quelle guide, sono cambiate quattro cose.

L'assegnazione automatica degli helper è disattivata e, nei kernel attuali, non può essere riattivata. Il kernel l'ha disabilitata per impostazione predefinita nel 2016. Il commit di Pablo Neira Ayuso "netfilter: remove nf_conntrack_helper sysctl and modparam toggles" (agosto 2022) ha poi rimosso del tutto l'interruttore, specificando che "gli utenti devono ora affidarsi alla configurazione esplicita degli helper conntrack tramite il ruleset". Il sysctl nf_conntrack_helper è presente in Linux 5.19 e assente da Linux 6.0 in poi; inoltre, la documentazione dei sysctl conntrack del kernel non lo elenca più. Caricare il modulo, da solo, non produce alcun effetto.

Puoi verificare quale tipo di kernel stai usando. Esegui sysctl net.netfilter.nf_conntrack_helper. Una risposta sysctl: cannot stat /proc/sys/net/netfilter/nf_conntrack_helper: No such file or directory indica che nel kernel non è più disponibile alcuna assegnazione automatica degli helper da attivare. Se invece ottieni un numero, stai usando un kernel precedente a 6.0: l'interruttore è ancora presente e il suo valore predefinito è 0.

Anche i frontend dei firewall lo hanno deprecato. man ufw-framework su Ubuntu 24.04 definisce la riga IPT_MODULES in /etc/default/ufw come segue: "Il caricamento incondizionato dei moduli di tracciamento delle connessioni (nf_conntrack_*) in questo modo è deprecato", e aggiunge che le regole degli helper "devono essere gestite nei FILE DELLE REGOLE". firewalld documenta AutomaticHelpers in firewalld.conf come "Deprecato. Questa opzione viene ignorata e non è più utilizzata." Oggi associare un helper significa scrivere manualmente una regola esplicita con il target CT. È più laborioso della correzione descritta di seguito e smette di funzionare non appena abiliti TLS. iptables e nftables su Ubuntu spiega dove si trovano effettivamente queste regole.

TLS chiude la questione. Un helper funziona leggendo il canale di controllo come testo. Se cifri quel canale, l'helper vede testo cifrato e non può individuare la porta. Non esiste una correzione e non dovrebbe esistere: un middlebox in grado di leggere il tuo canale di controllo è un middlebox che ha letto la tua password.

Dichiarare un intervallo di porte passive sul server

Ogni server FTP può essere configurato per scegliere le porte passive da un intervallo specificato. I nomi delle opzioni variano, quindi consultare la documentazione del server effettivamente in uso.

vsftpd, in /etc/vsftpd.conf:

pasv_enable=YES
pasv_min_port=30000
pasv_max_port=30099

pasv_enable ha già come valore predefinito YES. Le due opzioni relative alle porte hanno come valore predefinito 0, cioè il comportamento “usa una porta qualsiasi” descritto sopra. Applicare la modifica con sudo systemctl restart vsftpd, quindi verificare che il servizio sia tornato attivo con systemctl status vsftpd. vsftpd rifiuta di avviarsi quando non riesce ad analizzare una riga di configurazione, invece di ignorarla. Se il riavvio non riesce, leggere journalctl -u vsftpd -n 20 per trovare la riga 500 OOPS: che indica l’opzione appena inserita.

ProFTPD, in proftpd.conf:

PassivePorts 30000 30099

ProFTPD non documenta alcun valore predefinito in questo caso: senza la direttiva, è il kernel a scegliere la porta. La documentazione di ProFTPD indica inoltre che, quando nessuna porta dell’intervallo è libera, il server utilizza una porta assegnata dal kernel e registra un messaggio. Un intervallo troppo piccolo causa quindi errori intermittenti invece di un errore immediato e chiaro, rendendo la diagnosi molto più difficile. Usare porte non privilegiate, a partire da 1024.

Pure-FTPd usa il flag -p first:last, documentato in man pure-ftpd come “Usa solo le porte comprese tra la prima e l’ultima dell’intervallo per i download in modalità passiva”, che “rende pure-ftpd più compatibile con i filtri dei pacchetti”. Le build fornite dai pacchetti di distribuzione racchiudono solitamente questo flag in un file di configurazione. Consultare quindi la documentazione della propria distribuzione per conoscere il nome del file, invece di indovinarlo.

Quante porte servono? Una per ogni connessione dati attiva. Una porta TCP chiusa resta nello stato TIME_WAIT per un paio di minuti prima di poter essere riutilizzata, quindi prevedere un numero di porte pari a diverse volte il picco previsto. Cento porte sono sufficienti per alcuni utenti, mentre un server pubblico molto utilizzato ne richiede molte di più. In questo caso vsftpd è meno tollerante di ProFTPD: il codice sorgente prova alcune porte casuali all’interno dell’intervallo e, se sono tutte occupate, termina la sessione con 500 OOPS: vsf_sysutil_bind invece di utilizzare una porta esterna all’intervallo. Su entrambi i server, un intervallo troppo piccolo interrompe i trasferimenti proprio nei momenti di maggiore utilizzo.

Dove collocare l’intervallo? Eseguire prima sysctl net.ipv4.ip_local_port_range. Su un’installazione Ubuntu standard restituisce 32768 60999, cioè le porte assegnate dal kernel per le connessioni in uscita. Un intervallo passivo compreso in questa finestra può entrare in conflitto con una connessione in uscita che utilizza già la porta. Mantenerlo quindi al di sotto di tale intervallo. 30000-30099 è libero su un sistema predefinito. Verificare il valore sul proprio sistema invece di considerare affidabile questo numero.

Aprire lo stesso intervallo nel firewall

ufw definisce un intervallo con i due punti e il relativo manuale specifica che un intervallo o un elenco «può essere usato anche per specificare più porte; in questo caso il protocollo è obbligatorio»:

sudo ufw allow 21/tcp
sudo ufw allow 30000:30099/tcp
sudo ufw status verbose

ufw status verbose dovrebbe ora elencare entrambe le regole. Lo stesso comando senza /tcp viene rifiutato con un errore che richiede di specificare tcp o udp, perché ufw non sceglie il protocollo in modo automatico. sintassi delle regole ufw su un VPS illustra gli altri casi.

firewalld definisce l’intervallo con un trattino e richiede un reload:

sudo firewall-cmd --permanent --add-service=ftp
sudo firewall-cmd --permanent --add-port=30000-30099/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

--add-service=ftp apre 21/tcp e richiede l’helper ftp indicato dalla definizione del servizio fornita con il prodotto. Non apre l’intervallo per le connessioni passive, quindi da solo lascia la situazione invariata. zone e servizi firewalld su un VPS fornisce il quadro completo.

nftables in forma diretta, nella catena input:

tcp dport { 21, 30000-30099 } accept

Occorre considerare anche un altro firewall: la maggior parte dei provider gestisce un firewall di rete nel pannello di controllo, esterno al sistema operativo. Se le regole sul server sono corrette ma i pacchetti continuano a non arrivare, aprire lo stesso intervallo anche in quel firewall.

Indicare al server il proprio indirizzo pubblico quando si trova dietro NAT

Eseguire ip -4 addr show sul server. Se l'indirizzo dell'interfaccia è quello a cui si connettono i client, saltare questa sezione. Se l'interfaccia ha un indirizzo privato (10.x, da 172.16 a 172.31.x, 192.168.x) e la piattaforma vi associa un indirizzo pubblico, il server non conosce il proprio indirizzo pubblico. La documentazione di vsftpd indica che il valore predefinito di pasv_address è «the address is taken from the incoming connected socket», quindi la risposta 227 contiene l'indirizzo privato e il client viene indirizzato verso una destinazione che non può raggiungere.

FileZilla indica questa situazione con il messaggio seguente:

Server sent passive reply with unroutable address. Using server address instead.

FileZilla corregge il problema e prosegue. Molti altri client non lo fanno. Si connettono a 10.0.0.5 e rimangono in attesa.

Anche curl nasconde il problema, aspetto rilevante se lo si usa per i test. Il manuale indica che --ftp-skip-pasv-ip «is enabled by default (added in 7.74.0)», quindi curl ignora l'indirizzo nella risposta 227 e riutilizza quello della connessione di controllo. Un trasferimento che funziona con curl può comunque non riuscire in un client grafico per questo unico motivo.

Impostare esplicitamente l'indirizzo. vsftpd accetta pasv_address=203.0.113.10, oltre a pasv_addr_resolve=YES (valore predefinito NO) se si preferisce specificare un hostname. ProFTPD accetta MasqueradeAddress, che può contenere un indirizzo, un nome DNS o il nome di un'interfaccia. Pure-FTPd accetta -P, documentato per il caso in cui «the server is behind a masquerading (NAT) box». EPSV evita completamente il problema, perché la risposta non contiene alcun campo indirizzo; tuttavia non si può fare affidamento su questo comportamento, poiché è il client a decidere quale comando inviare.

Cosa cambia con TLS

FTPS è FTP su TLS (Transport Layer Security). Il client si connette alla porta 21 come di consueto, invia AUTH TLS per proteggere il canale di controllo, quindi invia PROT P per cifrare anche il canale dati. FTP in chiaro trasmette la password sulla rete come testo leggibile; se devi continuare a usare FTP, esegui FTPS. vsftpd viene fornito con ssl_enable impostato su NO.

Ne conseguono due aspetti. Nessun helper per il connection tracking può funzionare: è lo stesso problema descritto sopra, visto dall'altro lato. Inoltre, sudo tcpdump -nAi any 'tcp port 21' non mostrerà più la risposta 227; quando devi sapere quale indirizzo e quale porta ha annunciato il server, consulta il log del server invece del traffico di rete.

Test della modifica dall'esterno

Eseguire questi comandi da un'altra macchina. Eseguire i test direttamente dal server bypassa il firewall che si sta cercando di correggere.

sudo ss -ltnp | grep :21
curl -v --disable-epsv --user ftpuser:secret ftp://example.com/
nc -vz example.com 30000

ss dovrebbe mostrare il demone FTP in ascolto sulla porta 21. Quando il server è inattivo, nessun processo resta in ascolto sull'intervallo passivo, perché questi socket vengono creati per un trasferimento e chiusi al termine.

--disable-epsv forza curl a usare il percorso PASV, che è quello che espone il problema dell'indirizzo. Il trace stampa la risposta del server, quindi l'indirizzo e la porta a cui curl si connette:

< 227 Entering Passive Mode (203,0,113,10,117,52)

117 * 256 + 52 = 30004, all'interno dell'intervallo dichiarato. Un indirizzo privato su quella riga indica che pasv_address non è impostata. Una porta esterna all'intervallo indica che il server non ha mai letto la modifica alla configurazione; verificare quindi di aver modificato il file utilizzato dal servizio in esecuzione.

nc risponde direttamente alla domanda sul firewall. Un Connection refused immediato indica che il pacchetto ha raggiunto il server, ma non ha trovato alcun processo in ascolto: è il risultato corretto per una porta passiva inattiva e significa che la regola funziona. Un'attesa fino a quando nc rinuncia indica che qualcosa ha eliminato il pacchetto senza risposta. Si tratta di un firewall, quello del server oppure quello configurato nel pannello del provider. La distinzione è la stessa descritta in connessione SSH rifiutata o scaduta e si applica a ogni porta.

È ancora opportuno usare FTP?

Per i nuovi progetti, no. SFTP (SSH file transfer protocol) opera all'interno di un'unica connessione SSH sulla porta 22. Non esistono un secondo canale, un intervallo passivo, un'impostazione NAT o un demone aggiuntivo da proteggere, perché OpenSSH fornisce già questa funzionalità. sftp user@example.com funziona su un sistema in cui non è mai stato configurato alcun servizio di trasferimento file. Per fornire a qualcuno soltanto dei file, sshd_config acquisisce ForceCommand internal-sftp insieme a ChrootDirectory. La directory deve essere di proprietà di root e non deve essere scrivibile dall'utente; in caso contrario, sshd rifiuta la sessione e registra una riga bad ownership or modes for chroot directory.

FTP conserva una sua validità quando l'altra parte non può cambiare. Scanner e stampanti multifunzione vengono distribuiti con firmware che supporta FTP e nient'altro. Le apparecchiature di laboratorio e industriali eseguono spesso un'immagine fissa che nessuno sottoporrà nuovamente a certificazione. I partner commerciali pubblicano un endpoint FTPS e non aggiungeranno un protocollo per un singolo fornitore. In ciascuno di questi casi, l'intervallo passivo e la regola firewall corrispondente costituiscono l'intero lavoro, e la versione da usare è FTPS, non FTP in chiaro. Il design a due canali è una scelta del 1980, già presente in RFC 765 cinque anni prima che RFC 959 la portasse avanti; oggi opera in un mondo che non aveva mai previsto, una storia descritta in la storia dei protocolli di trasferimento file.

FAQ

Perché FTP esegue il login ma il listing della directory resta bloccato?

Il login usa soltanto la connessione di controllo sulla porta 21, consentita dal firewall. Il listing della directory richiede una seconda connessione TCP su un'altra porta, che viene bloccata. Dichiara un intervallo di porte passive sul server FTP e apri lo stesso intervallo nel firewall: il listing verrà completato. Un listing bloccato indica un problema del canale dati, non della password.

Quali porte devo aprire per la modalità passiva di FTP?

La porta 21 per il canale di controllo, oltre all'intervallo configurato per le connessioni dati passive. Non esiste un intervallo standard, perché lo scegli tu. Un intervallo come 30000-30099 è adatto: dimensionarlo in base al numero massimo di trasferimenti simultanei e assicurati che non si sovrapponga all'intervallo di porte in uscita del kernel, leggibile con sysctl net.ipv4.ip_local_port_range. Se il provider mette a disposizione un firewall di rete nel pannello di controllo, apri lo stesso intervallo anche lì.

Ho ancora bisogno di nf_conntrack_ftp?

No, e con un kernel attuale non puoi farci affidamento. L'assegnazione automatica degli helper è disabilitata per impostazione predefinita e, da Linux 6.0, l'opzione net.netfilter.nf_conntrack_helper è stata rimossa; di conseguenza sysctl segnala che il file non esiste. Il manuale di ufw considera deprecato il caricamento incondizionato di questi moduli e firewalld ignora completamente AutomaticHelpers. Un helper deve inoltre leggere il canale di controllo come testo in chiaro, quindi smette di funzionare non appena abiliti FTPS. Dichiara invece un intervallo di porte passive.

Perché il client FTP segnala che la risposta passiva contiene un indirizzo non instradabile?

Il server ha risposto a PASV con l'indirizzo rilevato sulla propria interfaccia, che è privato. Questo accade quando la piattaforma associa un indirizzo pubblico a un indirizzo privato. Imposta esplicitamente l'indirizzo pubblico: pasv_address in vsftpd, MasqueradeAddress in ProFTPD oppure -P in Pure-FTPd. FileZilla aggira il problema riutilizzando l'indirizzo a cui si era già connesso e registra "Using server address instead". Per questo alcuni client continuano a funzionare nonostante la configurazione errata, mentre altri restano bloccati.

Devo usare FTPS o SFTP?

SFTP per tutto ciò che controlli su entrambe le estremità: usa una sola connessione SSH sulla porta 22, non richiede l'apertura di un canale dati ed è già disponibile. FTPS è FTP su TLS, quindi mantiene il modello a due canali e tutti i problemi di firewall associati. Sceglilo quando l'altra parte non supporta nient'altro. Non usare FTP in chiaro su Internet, perché la password attraversa la rete come testo leggibile.

Questo articolo ti è stato utile?