Pourquoi les listes FTP se bloquent derrière une passerelle VPN qui fait du NAT
La connexion et PWD réussissent tandis que LIST et RETR se bloquent quand le NAT ne réécrit que les en-têtes. Voyez où doit se trouver l’auxiliaire FTP et comment corriger le mode passif.
La connexion fonctionne, PWD fonctionne, puis LIST se bloque jusqu’à ce que le client abandonne ou passe dans un autre mode de données. Cette séparation est la signature : la connexion de contrôle vers le port 21 est saine, alors que la connexion de données se construit depuis une adresse ou un port que l’autre côté ne peut pas atteindre. Derrière une passerelle VPN qui fait aussi du NAT, le coupable habituel est une commande FTP dont la charge utile nomme une adresse de tunnel comme 10.8.0.6. La traduction des en-têtes ne touche jamais cette valeur.
Ce qui suit, c’est d’où vient cette valeur et quelle boîte a le droit de la changer.
Ce qui casse, c’est la charge utile, pas le tunnel
FTP place le point de terminaison de données à l’intérieur du flux de contrôle. En mode actif, le client envoie PORT avec sa propre adresse et son port, et le serveur rappelle ce couple. En mode passif, le serveur répond 227 avec un couple, et le client rappelle celui-là à la place.
Les deux formes portent le même type d’énoncé : connecte-toi à cette adresse, sur ce port. Un appareil qui ne réécrit que les en-têtes IP et TCP laisse l’énoncé intact, si bien qu’un côté continue d’essayer d’atteindre une adresse qui n’existe que de l’autre côté d’un tunnel. La connexion de données se bloque après que la connexion de contrôle a déjà été déclarée saine.
Trois modes, trois charges utiles
Le tableau ci-dessous montre à quel côté il est demandé d’appeler, et ce qu’un NAT qui ne réécrit que les en-têtes peut y faire.
Lisez la dernière colonne comme ce qui échoue en premier. En mode actif, c’est le serveur qui appelle une adresse privée ; en mode passif, c’est le client ; avec FTPS, la charge utile est du texte chiffré et la boîte intermédiaire a encore moins de matière.
| Mode | Value in the control stream | Who dials whom | Header-only NAT leaves |
|---|---|---|---|
| Active (PORT) | client address and port | server dials the client | a server dialing an unreachable tunnel address |
| Passive (227) | server address and port | client dials the server | a client dialing an address it cannot route to |
| FTPS | the same values, inside TLS | as above | ciphertext, so no rewrite happens at all |
Placez l’auxiliaire là où la traduction se produit
Sous Linux, la réécriture de la charge utile est faite par l’auxiliaire nf_conntrack_ftp. Il surveille la connexion de contrôle, apprend le port négocié, crée une attente pour le flux de données et, sur une boîte NAT, réécrit l’adresse et le port à l’intérieur de la charge utile. Il n’aide que sur l’appareil qui traduit l’adresse du client. Le charger sur le client, ou sur un routeur qui ne fait que transmettre le flux, ne change rien à la session.
Ces trois commandes montrent si le module est présent, s’il est rattaché et si une attente existe pendant qu’une session est ouverte :
modprobe nf_conntrack_ftp
lsmod | grep nf_conntrack_ftp
conntrack -L expect | grep ftp
Charger le module n’est pas la même chose que le rattacher. Les noyaux à partir de 4.7 sont livrés avec net.netfilter.nf_conntrack_helper=0, donc l’auxiliaire attend une règle explicite, par exemple iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp. Si la liste d’attentes reste vide pendant qu’un transfert est tenté, c’est le rattachement qu’il faut vérifier, pas le module.
Mode passif : dites au serveur quoi annoncer
Le mode passif est plus facile à rendre déterministe parce qu’on peut dire au serveur quoi mettre dans la réponse 227. Dans vsftpd, c’est pasv_address, avec pasv_min_port et pasv_max_port ; ProFTPD utilise MasqueradeAddress et PassivePorts. Réglez-les d’abord, car une adresse annoncée correcte supprime le besoin de réécrire quoi que ce soit de ce côté.
Laissez ensuite passer exactement cette plage de ports par la passerelle, par exemple -A FORWARD -i tun0 -p tcp --dport 30000:30100 -j ACCEPT, pour que la règle corresponde à ce que le serveur annonce.
Les deux réglages doivent concorder. Un serveur à qui l’on dit d’annoncer 30000-30100 alors que la passerelle autorise 40000-40100 échoue de la façon la moins utile : la conversation de contrôle paraît saine et chaque connexion de données meurt. Comparez les nombres avant de déboguer quoi que ce soit d’autre.
Deux signatures de panne, et ce que FTPS supprime
Un blocage sur LIST désigne la première connexion de données de la session, là où la réécriture d’adresse et l’attente doivent toutes deux fonctionner. Un blocage sur RETR après un LIST qui fonctionne désigne le transfert lui-même, c’est-à-dire la plage passive ou le MTU du tunnel. Cette seconde signature n’est pas un problème de charge utile, et les réglages de l’auxiliaire ne la corrigeront pas.
FTP sur TLS supprime la charge utile que lit l’auxiliaire. Une boîte intermédiaire ne peut pas réécrire une valeur PORT ou PASV qu’elle ne peut pas déchiffrer, donc il reste un mandataire qui termine TLS, un serveur qui annonce une adresse joignable dans une plage bornée, ou un autre protocole de transfert.
Un court ordre de vérifications
Travaillez du symptôme vers l’extérieur. Confirmez que LIST échoue alors que PWD réussit, capturez l’adresse dans la charge utile PORT ou 227, et demandez quel appareil traduit cette adresse. Rattachez-y l’auxiliaire, surveillez la liste d’attentes pendant un transfert, puis corrigez le mode passif sur le serveur et reflétez la plage dans la règle de la passerelle.
Gardez la panne du chemin de données séparée de la panne de transfert massif, car elles vous mènent à des réglages différents.